home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr44 / frasrc19.zip / LINE3D.C < prev    next >
C/C++ Source or Header  |  1995-03-04  |  96KB  |  2,701 lines

  1. /************************************************************************/
  2. /* This file contains a 3D replacement for the out_line function called */
  3. /* by the decoder. The purpose is to apply various 3D transformations   */
  4. /* before displaying points. Called once per line of the input file.    */
  5. /*                                                                      */
  6. /* Original Author Tim Wegner, with extensive help from Marc Reinig.    */
  7. /*    July 1994 - TW broke out several pieces of code and added pragma  */
  8. /*                to eliminate compiler warnings. Did a long-overdue    */
  9. /*                formatting cleanup.                                   */
  10. /************************************************************************/
  11.  
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <limits.h>
  15. #ifndef XFRACT
  16. #include <dos.h>
  17. #endif
  18. #include "fractint.h"
  19. #include "prototyp.h"
  20.  
  21. struct point
  22. {
  23.    int x;
  24.    int y;
  25.    int color;
  26. };
  27.  
  28. struct f_point
  29. {
  30.    float x;
  31.    float y;
  32.    float color;
  33. };
  34.  
  35. struct minmax
  36. {
  37.    int minx;
  38.    int maxx;
  39. };
  40.  
  41. /* routines in this module */
  42. int line3d(BYTE *, unsigned);
  43. int _fastcall targa_color(int, int, int);
  44. int targa_validate(char *);
  45. static int first_time(int, VECTOR);
  46. static int H_R(BYTE *, BYTE *, BYTE *, unsigned long, unsigned long, unsigned long);
  47. static int line3dmem(void);
  48. static int R_H(BYTE, BYTE, BYTE, unsigned long *, unsigned long *, unsigned long *);
  49. static int set_pixel_buff(BYTE *, BYTE far *, unsigned);
  50. static int startdisk1(char *, FILE *, int);
  51. static int _fastcall end_object(int);
  52. static int _fastcall offscreen(struct point);
  53. static int _fastcall out_triangle(struct f_point, struct f_point, struct f_point, int, int, int);
  54. static int _fastcall RAY_Header(void);
  55. static int _fastcall start_object(void);
  56. static void corners(MATRIX, int, double *, double *, double *, double *, double *, double *);
  57. static void draw_light_box(double *, double *, MATRIX);
  58. static void draw_rect(VECTOR, VECTOR, VECTOR, VECTOR, int, int);
  59. static void File_Error(char *, int);
  60. static void line3d_cleanup(void);
  61. static void _fastcall clipcolor(int, int, int);
  62. static void _fastcall interpcolor(int, int, int);
  63. static void _fastcall putatriangle(struct point, struct point, struct point, int);
  64. static void _fastcall putminmax(int, int, int);
  65. static void _fastcall triangle_bounds(float pt_t[3][3]);
  66. static void _fastcall T_clipcolor(int, int, int);
  67. static void _fastcall vdraw_line(double *, double *, int color);
  68. static void (_fastcall * fillplot) (int, int, int);
  69. static void (_fastcall * normalplot) (int, int, int);
  70.  
  71. /* static variables */
  72. static float deltaphi;          /* increment of latitude, longitude */
  73. static double rscale;           /* surface roughness factor */
  74. static long xcenter, ycenter;   /* circle center */
  75. static double sclx, scly, sclz; /* scale factors */
  76. static double R;                /* radius values */
  77. static double Rfactor;          /* for intermediate calculation */
  78. static LMATRIX llm;             /* "" */
  79. static LVECTOR lview;           /* for perspective views */
  80. static double zcutoff;          /* perspective backside cutoff value */
  81. static float twocosdeltaphi;
  82. static float cosphi, sinphi;    /* precalculated sin/cos of longitude */
  83. static float oldcosphi1, oldsinphi1;
  84. static float oldcosphi2, oldsinphi2;
  85. static BYTE far *fraction;      /* float version of pixels array */
  86. static float min_xyz[3], max_xyz[3];        /* For Raytrace output */
  87. static int line_length1;
  88. static int T_header_24 = 18;/* Size of current Targa-24 header */
  89. static FILE *File_Ptr1 = NULL;
  90. static unsigned int IAmbient;
  91. static int rand_factor;
  92. static int HAZE_MULT;
  93. static void File_Error(char *File_Name1, int ERROR);
  94. static BYTE T24 = 24;
  95. static BYTE T32 = 32;
  96. static BYTE upr_lwr[4];
  97. static int T_Safe; /* Original Targa Image successfully copied to targa_temp */
  98. static void draw_rect(VECTOR, VECTOR, VECTOR, VECTOR, int, int);
  99. static VECTOR light_direction;
  100. static BYTE Real_Color;  /* Actual color of cur pixel */
  101. static int RO, CO, CO_MAX;  /* For use in Acrospin support */
  102. static FCODE acro_s1[] =
  103.    {"Set Layer 1\nSet Color 2\nEndpointList X Y Z Name\n"};
  104. static FCODE acro_s2[] = {"LineList From To\n"};
  105. static FCODE s3[] = {"{ Created by FRACTINT Ver. "};
  106. static FCODE s3a[] = {" }\n\n"};
  107. #ifndef XFRACT
  108. static char banner[] = "%Fs%#4.2f%Fs";
  109. #else
  110. static char banner[] = "%s%#4.2f%s";
  111. #endif
  112. static int localpreviewfactor;
  113. static int zcoord = 256;
  114. static double aspect;       /* aspect ratio */
  115. static int evenoddrow;
  116. static float far *sinthetaarray;    /* all sine thetas go here  */
  117. static float far *costhetaarray;    /* all cosine thetas go here */
  118. static double rXrscale;     /* precalculation factor */
  119. static int persp;  /* flag for indicating perspective transformations */
  120. static struct point p1, p2, p3;
  121. static struct f_point f_bad;/* out of range value */
  122. static struct point bad;    /* out of range value */
  123. static long num_tris; /* number of triangles output to ray trace file */
  124.  
  125. /* global variables defined here */
  126. struct f_point far *f_lastrow;
  127. void (_fastcall * standardplot) (int, int, int);
  128. MATRIX m; /* transformation matrix */
  129. void (*mult_vec) (VECTOR) = mult_vec_c;
  130. int Ambient;
  131. int RANDOMIZE;
  132. int haze;
  133. int Real_V = 0; /* mrr Actual value of V for fillytpe>4 monochrome images */
  134. char light_name[80] = "fract001";
  135. int Targa_Overlay, error;
  136. char targa_temp[14] = "fractemp.tga";
  137. int P = 250; /* Perspective dist used when viewing light vector */
  138. BYTE back_color[3];
  139. char ray_name[80] = "fract001";
  140. char preview = 0;
  141. char showbox = 0;
  142. int previewfactor = 20;
  143. int xadjust = 0;
  144. int yadjust = 0;
  145. int xxadjust;
  146. int yyadjust;
  147. int xshift;
  148. int yshift;
  149. int bad_value = -10000; /* set bad values to this */
  150. int bad_check = -3000;  /* check values against this to determine if good */
  151. struct point far *lastrow; /* this array remembers the previous line */
  152. int RAY = 0;        /* Flag to generate Ray trace compatible files in 3d */
  153. int BRIEF = 0;      /* 1 = short ray trace files */
  154.  
  155. /* array of min and max x values used in triangle fill */
  156. struct minmax far *minmax_x;
  157. VECTOR view;                /* position of observer for perspective */
  158. VECTOR cross;
  159. VECTOR tmpcross;
  160.  
  161. struct point oldlast = { 0, 0, 0 }; /* old pixels */
  162.  
  163.  
  164. int line3d(BYTE * pixels, unsigned linelen)
  165. {
  166.    int tout;                    /* triangle has been sent to ray trace file */
  167.    int RND;
  168.    float f_water = (float)0.0;        /* transformed WATERLINE for ray trace files */
  169.    double r0;
  170.    int xcenter0 = 0;
  171.    int ycenter0 = 0;      /* Unfudged versions */
  172.    double r;                    /* sphere radius */
  173.    float costheta, sintheta;    /* precalculated sin/cos of latitude */
  174.    int next;                    /* used by preview and grid */
  175.    int col;                     /* current column (original GIF) */
  176.    struct point cur;            /* current pixels */
  177.    struct point old;            /* old pixels */
  178.    struct f_point f_cur;
  179.    struct f_point f_old;
  180.    VECTOR v;                    /* double vector */
  181.    VECTOR v1, v2;
  182.    VECTOR crossavg;
  183.    char crossnotinit;           /* flag for crossavg init indication */
  184.    LVECTOR lv;                  /* long equivalent of v */
  185.    LVECTOR lv0;                 /* long equivalent of v */
  186.    int lastdot;
  187.    long fudge;
  188.  
  189.    fudge = 1L << 16;
  190.  
  191.  
  192.    if (transparent[0] || transparent[1])
  193.       plot = normalplot = T_clipcolor;  /* Use transparent plot function */
  194.    else                         /* Use the usual FRACTINT plot function with
  195.                                  * clipping */
  196.       plot = normalplot = clipcolor;
  197.  
  198.    currow = rowcount;           /* use separate variable to allow for
  199.                                  * pot16bit files */
  200.    if (pot16bit)
  201.       currow >>= 1;
  202.  
  203.    /************************************************************************/
  204.    /* This IF clause is executed ONCE per image. All precalculations are   */
  205.    /* done here, with out any special concern about speed. DANGER -        */
  206.    /* communication with the rest of the program is generally via static   */
  207.    /* or global variables.                                                 */
  208.    /************************************************************************/
  209.    if (rowcount++ == 0)
  210.    {
  211.       int err;
  212.       if ((err = first_time(linelen, v)) != 0)
  213.          return (err);
  214.       tout = 0;
  215.       crossavg[0] = 0;
  216.       crossavg[1] = 0;
  217.       crossavg[2] = 0;
  218.       xcenter0 = (int) (xcenter = xdots / 2 + xshift);
  219.       ycenter0 = (int) (ycenter = ydots / 2 - yshift);
  220.  
  221.    }
  222.    /* make sure these pixel coordinates are out of range */
  223.    old = bad;
  224.    f_old = f_bad;
  225.  
  226.    /* copies pixels buffer to float type fraction buffer for fill purposes */
  227.    if (pot16bit)
  228.    {
  229.       if (set_pixel_buff(pixels, fraction, linelen))
  230.          return (0);
  231.    }
  232.    else if (grayflag)           /* convert color numbers to grayscale values */
  233.       for (col = 0; col < (int) linelen; col++)
  234.       {
  235.          int pal, colornum;
  236.          colornum = pixels[col];
  237.          /* effectively (30*R + 59*G + 11*B)/100 scaled 0 to 255 */
  238.          pal = ((int) dacbox[colornum][0] * 77 +
  239.                 (int) dacbox[colornum][1] * 151 +
  240.                 (int) dacbox[colornum][2] * 28);
  241.          pal >>= 6;
  242.          pixels[col] = (BYTE) pal;
  243.       }
  244.    crossnotinit = 1;
  245.    col = 0;
  246.  
  247.    CO = 0;
  248.  
  249.    /*************************************************************************/
  250.    /* This section of code allows the operation of a preview mode when the  */
  251.    /* preview flag is set. Enabled, it allows the drawing of only the first */
  252.    /* line of the source image, then every 10th line, until and including   */
  253.    /* the last line. For the undrawn lines, only necessary calculations are */
  254.    /* made. As a bonus, in non-sphere mode a box is drawn to help visualize */
  255.    /* the effects of 3D transformations. Thanks to Marc Reinig for this idea*/
  256.    /* and code -- BTW, Marc did NOT put the goto in, but WE did, to avoid   */
  257.    /* copying code here, and to avoid a HUGE "if-then" construct. Besides,  */
  258.    /* we have ALREADY sinned, so why not sin some more?                     */
  259.    /*************************************************************************/
  260.    lastdot = min(xdots - 1, (int) linelen - 1);
  261.    if (FILLTYPE >= 5)
  262.       if (haze && Targa_Out)
  263.       {
  264.          HAZE_MULT = (int) (haze * (
  265.                                       (float) ((long) (ydots - 1 - currow) *
  266.                                                (long) (ydots - 1 - currow)) /
  267.                         (float) ((long) (ydots - 1) * (long) (ydots - 1))));
  268.          HAZE_MULT = 100 - HAZE_MULT;
  269.       }
  270.  
  271.    if (previewfactor >= ydots || previewfactor > lastdot)
  272.       previewfactor = min(ydots - 1, lastdot);
  273.  
  274.    localpreviewfactor = ydots / previewfactor;
  275.  
  276.    tout = 0;
  277.    /* Insure last line is drawn in preview and filltypes <0  */
  278.    if ((RAY || preview || FILLTYPE < 0) && (currow != ydots - 1) &&
  279.        (currow % localpreviewfactor) && /* Draw mod preview lines */
  280.        !(!RAY && (FILLTYPE > 4) && (currow == 1)))
  281.       /* Get init geometry in lightsource modes */
  282.       goto reallythebottom;     /* skip over most of the line3d calcs */
  283.    if (dotmode == 11)
  284.    {
  285.       static FCODE mapping[] = {"mapping to 3d, reading line "};
  286.       char s[40];
  287. #ifndef XFRACT
  288.       sprintf(s, "%Fs%d", (char far *)mapping, currow);
  289. #else
  290.       sprintf(s, "%s%d", mapping, currow);
  291. #endif
  292.       dvid_status(1, s);
  293.    }
  294.  
  295.    if (!col && RAY && currow != 0)
  296.       start_object();
  297.       /* PROCESS ROW LOOP BEGINS HERE */
  298.       while (col < (int) linelen)
  299.       {
  300.          if ((RAY || preview || FILLTYPE < 0) &&
  301.              (col != lastdot) &&/* if this is not the last col */
  302.          /* if not the 1st or mod factor col */
  303.              (col % (int) (aspect * localpreviewfactor)) &&
  304.              (!(!RAY && FILLTYPE > 4 && col == 1)))
  305.             goto loopbottom;
  306.  
  307.          f_cur.color = cur.color = Real_Color = pixels[col];
  308.  
  309.          if (RAY || preview || FILLTYPE < 0)
  310.          {
  311.             next = (int) (col + aspect * localpreviewfactor);
  312.             if (next == col)
  313.                next = col + 1;
  314.          }
  315.          else
  316.             next = col + 1;
  317.          if (next >= lastdot)
  318.             next = lastdot;
  319.  
  320.          if (cur.color > 0 && cur.color < WATERLINE)
  321.             f_cur.color = cur.color = Real_Color = (BYTE)WATERLINE; /* "lake" */
  322.          else if (pot16bit)
  323.             f_cur.color += ((float) fraction[col]) / (float) (1 << 8);
  324.  
  325.          if (SPHERE)            /* sphere case */
  326.          {
  327.             sintheta = sinthetaarray[col];
  328.             costheta = costhetaarray[col];
  329.  
  330.             if (sinphi < 0 && !(RAY || FILLTYPE < 0))
  331.             {
  332.                cur = bad;
  333.                f_cur = f_bad;
  334.                goto loopbottom; /* another goto ! */
  335.             }
  336.             /************************************************************/
  337.             /* KEEP THIS FOR DOCS - original formula --                 */
  338.             /* if(rscale < 0.0)                                         */
  339.             /* r = 1.0+((double)cur.color/(double)zcoord)*rscale;       */
  340.             /* else                                                     */
  341.             /* r = 1.0-rscale+((double)cur.color/(double)zcoord)*rscale;*/
  342.             /* R = (double)ydots/2;                                     */
  343.             /* r = r*R;                                                 */
  344.             /* cur.x = xdots/2 + sclx*r*sintheta*aspect + xup ;         */
  345.             /* cur.y = ydots/2 + scly*r*costheta*cosphi - yup ;         */
  346.             /************************************************************/
  347.  
  348.             if (rscale < 0.0)
  349.                r = R + Rfactor * (double) f_cur.color * costheta;
  350.             else if (rscale > 0.0)
  351.                r = R - rXrscale + Rfactor * (double) f_cur.color * costheta;
  352.             else
  353.                r = R;
  354.             /* Allow Ray trace to go through so display ok */
  355.             if (persp || RAY) 
  356.             {  /* mrr how do lv[] and cur and f_cur all relate */
  357.                /* NOTE: fudge was pre-calculated above in r and R */
  358.                /* (almost) guarantee negative */
  359.                lv[2] = (long) (-R - r * costheta * sinphi);     /* z */
  360.                if ((lv[2] > zcutoff) && !FILLTYPE < 0)
  361.                {
  362.                   cur = bad;
  363.                   f_cur = f_bad;
  364.                   goto loopbottom;      /* another goto ! */
  365.                }
  366.                lv[0] = (long) (xcenter + sintheta * sclx * r);  /* x */
  367.                lv[1] = (long) (ycenter + costheta * cosphi * scly * r); /* y */
  368.  
  369.                if ((FILLTYPE >= 5) || RAY)
  370.                {     /* calculate illumination normal before persp */
  371.  
  372.                   r0 = r / 65536L;
  373.                   f_cur.x = (float) (xcenter0 + sintheta * sclx * r0);
  374.                   f_cur.y = (float) (ycenter0 + costheta * cosphi * scly * r0);
  375.                   f_cur.color = (float) (-r0 * costheta * sinphi);
  376.                }
  377.                if (!(usr_floatflag || RAY))
  378.                {
  379.                   if (longpersp(lv, lview, 16) == -1)
  380.                   {
  381.                      cur = bad;
  382.                      f_cur = f_bad;
  383.                      goto loopbottom;   /* another goto ! */
  384.                   }
  385.                   cur.x = (int) (((lv[0] + 32768L) >> 16) + xxadjust);
  386.                   cur.y = (int) (((lv[1] + 32768L) >> 16) + yyadjust);
  387.                }
  388.                if (usr_floatflag || overflow || RAY)
  389.                {
  390.                   v[0] = lv[0];
  391.                   v[1] = lv[1];
  392.                   v[2] = lv[2];
  393.                   v[0] /= fudge;
  394.                   v[1] /= fudge;
  395.                   v[2] /= fudge;
  396.                   perspective(v);
  397.                   cur.x = (int) (v[0] + .5 + xxadjust);
  398.                   cur.y = (int) (v[1] + .5 + yyadjust);
  399.                }
  400.             }
  401.             /* mrr Not sure how this an 3rd if above relate */
  402.             else if (!(persp && RAY))   
  403.             {  
  404.                /* mrr Why the xx- and yyadjust here and not above? */
  405.                cur.x = (int) (f_cur.x = (float) (xcenter 
  406.                                  + sintheta * sclx * r + xxadjust));
  407.                cur.y = (int) (f_cur.y = (float) (ycenter 
  408.                                  + costheta * cosphi * scly * r + yyadjust));
  409.                if (FILLTYPE >= 5 || RAY)        /* mrr why do we do this for
  410.                                                  * filltype>5? */
  411.                   f_cur.color = (float) (-r * costheta * sinphi * sclz);
  412.                v[0] = v[1] = v[2] = 0;  /* MRR Why do we do this? */
  413.             }
  414.          }
  415.          else
  416.             /* non-sphere 3D */
  417.          {
  418.             if (!usr_floatflag && !RAY)
  419.             {
  420.                if (FILLTYPE >= 5)       /* flag to save vector before
  421.                                          * perspective */
  422.                   lv0[0] = 1;   /* in longvmultpersp calculation */
  423.                else
  424.                   lv0[0] = 0;
  425.  
  426.                /* use 32-bit multiply math to snap this out */
  427.                lv[0] = col;
  428.                lv[0] = lv[0] << 16;
  429.                lv[1] = currow;
  430.                lv[1] = lv[1] << 16;
  431.                if (filetype || pot16bit)        /* don't truncate fractional
  432.                                                  * part */
  433.                   lv[2] = (long) (f_cur.color * 65536.0);
  434.                else
  435.                   /* there IS no fractaional part here! */
  436.                {
  437.                   lv[2] = (long) f_cur.color;
  438.                   lv[2] = lv[2] << 16;
  439.                }
  440.  
  441.                if (longvmultpersp(lv, llm, lv0, lv, lview, 16) == -1)
  442.                {
  443.                   cur = bad;
  444.                   f_cur = f_bad;
  445.                   goto loopbottom;
  446.                }
  447.  
  448.                cur.x = (int) (((lv[0] + 32768L) >> 16) + xxadjust);
  449.                cur.y = (int) (((lv[1] + 32768L) >> 16) + yyadjust);
  450.                if (FILLTYPE >= 5 && !overflow)
  451.                {
  452.                   f_cur.x = (float) lv0[0];
  453.                   f_cur.x /= (float)65536.0;
  454.                   f_cur.y = (float) lv0[1];
  455.                   f_cur.y /= (float)65536.0;
  456.                   f_cur.color = (float) lv0[2];
  457.                   f_cur.color /= (float)65536.0;
  458.                }
  459.             }
  460.  
  461.             if (usr_floatflag || overflow || RAY)
  462.                /* do in float if integer math overflowed or doing Ray trace */
  463.             {
  464.                /* slow float version for comparison */
  465.                v[0] = col;
  466.                v[1] = currow;
  467.                v[2] = f_cur.color;      /* Actually the z value */
  468.  
  469.                mult_vec(v);     /* matrix*vector routine */
  470.  
  471.                if (FILLTYPE > 4 || RAY)
  472.                {
  473.                   f_cur.x = (float) v[0];
  474.                   f_cur.y = (float) v[1];
  475.                   f_cur.color = (float) v[2];
  476.  
  477.                   if (RAY == 6)
  478.                   {
  479.                      f_cur.x = f_cur.x * ((float)2.0 / xdots) - (float)1.0;
  480.                      f_cur.y = f_cur.y * ((float)2.0 / ydots) - (float)1.0;
  481.                      f_cur.color = -f_cur.color * ((float)2.0 / numcolors) - (float)1.0;
  482.                   }
  483.                }
  484.  
  485.                if (persp && !RAY)
  486.                   perspective(v);
  487.                cur.x = (int) (v[0] + xxadjust + .5);
  488.                cur.y = (int) (v[1] + yyadjust + .5);
  489.  
  490.                v[0] = 0;
  491.                v[1] = 0;
  492.                v[2] = WATERLINE;
  493.                mult_vec(v);
  494.                f_water = (float) v[2];
  495.             }
  496.          }
  497.  
  498.          if (RANDOMIZE)
  499.             if (cur.color > WATERLINE)
  500.             {
  501.                RND = rand15() >> 8;     /* 7-bit number */
  502.                RND = RND * RND >> rand_factor;  /* n-bit number */
  503.  
  504.                if (rand() & 1)
  505.                   RND = -RND;   /* Make +/- n-bit number */
  506.  
  507.                if ((int) (cur.color) + RND >= colors)
  508.                   cur.color = colors - 2;
  509.                else if ((int) (cur.color) + RND <= WATERLINE)
  510.                   cur.color = WATERLINE + 1;
  511.                else
  512.                   cur.color = cur.color + RND;
  513.                Real_Color = (BYTE)cur.color;
  514.             }
  515.  
  516.          if (RAY)
  517.          {
  518.             if (col && currow &&
  519.                 old.x > bad_check &&
  520.                 old.x < (xdots - bad_check) &&
  521.                 lastrow[col].x > bad_check &&
  522.                 lastrow[col].y > bad_check &&
  523.                 lastrow[col].x < (xdots - bad_check) &&
  524.                 lastrow[col].y < (ydots - bad_check))
  525.             {
  526.                /* Get rid of all the triangles in the plane at the base of
  527.                 * the object */
  528.  
  529.                if (f_cur.color == f_water &&
  530.                    f_lastrow[col].color == f_water &&
  531.                    f_lastrow[next].color == f_water)
  532.                   goto loopbottom;
  533.  
  534.                if (RAY != 6)    /* Output the vertex info */
  535.                   out_triangle(f_cur, f_old, f_lastrow[col],
  536.                                cur.color, old.color, lastrow[col].color);
  537.  
  538.                tout = 1;
  539.  
  540.                draw_line(old.x, old.y, cur.x, cur.y, old.color);
  541.                draw_line(old.x, old.y, lastrow[col].x,
  542.                          lastrow[col].y, old.color);
  543.                draw_line(lastrow[col].x, lastrow[col].y,
  544.                          cur.x, cur.y, cur.color);
  545.                num_tris++;
  546.             }
  547.  
  548.             if (col < lastdot && currow &&
  549.                 lastrow[col].x > bad_check &&
  550.                 lastrow[col].y > bad_check &&
  551.                 lastrow[col].x < (xdots - bad_check) &&
  552.                 lastrow[col].y < (ydots - bad_check) &&
  553.                 lastrow[next].x > bad_check &&
  554.                 lastrow[next].y > bad_check &&
  555.                 lastrow[next].x < (xdots - bad_check) &&
  556.                 lastrow[next].y < (ydots - bad_check))
  557.             {
  558.                /* Get rid of all the triangles in the plane at the base of
  559.                 * the object */
  560.  
  561.                if (f_cur.color == f_water &&
  562.                    f_lastrow[col].color == f_water &&
  563.                    f_lastrow[next].color == f_water)
  564.                   goto loopbottom;
  565.  
  566.                if (RAY != 6)    /* Output the vertex info */
  567.                   out_triangle(f_cur, f_lastrow[col], f_lastrow[next],
  568.                         cur.color, lastrow[col].color, lastrow[next].color);
  569.  
  570.                tout = 1;
  571.  
  572.                draw_line(lastrow[col].x, lastrow[col].y, cur.x, cur.y,
  573.                          cur.color);
  574.                draw_line(lastrow[next].x, lastrow[next].y, cur.x, cur.y,
  575.                          cur.color);
  576.                draw_line(lastrow[next].x, lastrow[next].y, lastrow[col].x,
  577.                          lastrow[col].y, lastrow[col].color);
  578.                num_tris++;
  579.             }
  580.  
  581.             if (RAY == 6)       /* Output vertex info for Acrospin */
  582.             {
  583.                fprintf(File_Ptr1, "% #4.4f % #4.4f % #4.4f R%dC%d\n",
  584.                        f_cur.x, f_cur.y, f_cur.color, RO, CO);
  585.                if (CO > CO_MAX)
  586.                   CO_MAX = CO;
  587.                CO++;
  588.             }
  589.             goto loopbottom;
  590.          }
  591.  
  592.          switch (FILLTYPE)
  593.          {
  594.          case -1:
  595.             if (col &&
  596.                 old.x > bad_check &&
  597.                 old.x < (xdots - bad_check))
  598.                draw_line(old.x, old.y, cur.x, cur.y, cur.color);
  599.             if (currow &&
  600.                 lastrow[col].x > bad_check &&
  601.                 lastrow[col].y > bad_check &&
  602.                 lastrow[col].x < (xdots - bad_check) &&
  603.                 lastrow[col].y < (ydots - bad_check))
  604.                draw_line(lastrow[col].x, lastrow[col].y, cur.x,
  605.                          cur.y, cur.color);
  606.             break;
  607.  
  608.          case 0:
  609.             (*plot) (cur.x, cur.y, cur.color);
  610.             break;
  611.  
  612.          case 1:                /* connect-a-dot */
  613.             if ((old.x < xdots) && (col) &&
  614.                 old.x > bad_check &&
  615.                 old.y > bad_check)      /* Don't draw from old to cur on col
  616.                                          * 0 */
  617.                draw_line(old.x, old.y, cur.x, cur.y, cur.color);
  618.             break;
  619.  
  620.          case 2:                /* with interpolation */
  621.          case 3:                /* no interpolation */
  622.             /*************************************************************/
  623.             /* "triangle fill" - consider four points: current point,    */
  624.             /* previous point same row, point opposite current point in  */
  625.             /* previous row, point after current point in previous row.  */
  626.             /* The object is to fill all points inside the two triangles.*/
  627.             /*                                                           */
  628.             /* lastrow[col].x/y___ lastrow[next]                         */
  629.             /* /        1                 /                              */
  630.             /* /                1         /                              */
  631.             /* /                       1  /                              */
  632.             /* oldrow/col ________ trow/col                              */
  633.             /*************************************************************/
  634.  
  635.             if (currow && !col)
  636.                putatriangle(lastrow[next], lastrow[col], cur, cur.color);
  637.             if (currow && col)  /* skip first row and first column */
  638.             {
  639.                if (col == 1)
  640.                   putatriangle(lastrow[col], oldlast, old, old.color);
  641.  
  642.                if (col < lastdot)
  643.                   putatriangle(lastrow[next], lastrow[col], cur, cur.color);
  644.                putatriangle(old, lastrow[col], cur, cur.color);
  645.             }
  646.             break;
  647.  
  648.          case 4:                /* "solid fill" */
  649.             if (SPHERE)
  650.             {
  651.                if (persp)
  652.                {
  653.                   old.x = (int) (xcenter >> 16);
  654.                   old.y = (int) (ycenter >> 16);
  655.                }
  656.                else
  657.                {
  658.                   old.x = (int) xcenter;
  659.                   old.y = (int) ycenter;
  660.                }
  661.             }
  662.             else
  663.             {
  664.                lv[0] = col;
  665.                lv[1] = currow;
  666.                lv[2] = 0;
  667.  
  668.                /* apply fudge bit shift for integer math */
  669.                lv[0] = lv[0] << 16;
  670.                lv[1] = lv[1] << 16;
  671.                /* Since 0, unnecessary lv[2] = lv[2] << 16; */
  672.  
  673.                if (longvmultpersp(lv, llm, lv0, lv, lview, 16))
  674.                {
  675.                   cur = bad;
  676.                   f_cur = f_bad;
  677.                   goto loopbottom;      /* another goto ! */
  678.                }
  679.  
  680.                /* Round and fudge back to original  */
  681.                old.x = (int) ((lv[0] + 32768L) >> 16);
  682.                old.y = (int) ((lv[1] + 32768L) >> 16);
  683.             }
  684.             if (old.x < 0)
  685.                old.x = 0;
  686.             if (old.x >= xdots)
  687.                old.x = xdots - 1;
  688.             if (old.y < 0)
  689.                old.y = 0;
  690.             if (old.y >= ydots)
  691.                old.y = ydots - 1;
  692.             draw_line(old.x, old.y, cur.x, cur.y, cur.color);
  693.             break;
  694.  
  695.          case 5:
  696.          case 6:
  697.             /* light-source modulated fill */
  698.             if (currow && col)  /* skip first row and first column */
  699.             {
  700.                if (f_cur.color < bad_check || f_old.color < bad_check ||
  701.                    f_lastrow[col].color < bad_check)
  702.                   break;
  703.  
  704.                v1[0] = f_cur.x - f_old.x;
  705.                v1[1] = f_cur.y - f_old.y;
  706.                v1[2] = f_cur.color - f_old.color;
  707.  
  708.                v2[0] = f_lastrow[col].x - f_cur.x;
  709.                v2[1] = f_lastrow[col].y - f_cur.y;
  710.                v2[2] = f_lastrow[col].color - f_cur.color;
  711.  
  712.                cross_product(v1, v2, cross);
  713.  
  714.                /* normalize cross - and check if non-zero */
  715.                if (normalize_vector(cross))
  716.                {
  717.                   if (debugflag)
  718.                   {
  719.                      static FCODE msg[] = {"debug, cur.color=bad"};
  720.                      stopmsg(0, msg);
  721.                   }
  722.                   cur.color = (int)(f_cur.color = bad.color);
  723.                }
  724.                else
  725.                {
  726.                   /* line-wise averaging scheme */
  727.                   if (LIGHTAVG > 0)
  728.                   {
  729.                      if (crossnotinit)
  730.                      {
  731.                         /* initialize array of old normal vectors */
  732.                         crossavg[0] = cross[0];
  733.                         crossavg[1] = cross[1];
  734.                         crossavg[2] = cross[2];
  735.                         crossnotinit = 0;
  736.                      }
  737.                      tmpcross[0] = (crossavg[0] * LIGHTAVG + cross[0]) /
  738.                         (LIGHTAVG + 1);
  739.                      tmpcross[1] = (crossavg[1] * LIGHTAVG + cross[1]) /
  740.                         (LIGHTAVG + 1);
  741.                      tmpcross[2] = (crossavg[2] * LIGHTAVG + cross[2]) /
  742.                         (LIGHTAVG + 1);
  743.                      cross[0] = tmpcross[0];
  744.                      cross[1] = tmpcross[1];
  745.                      cross[2] = tmpcross[2];
  746.                      if (normalize_vector(cross))
  747.                      {
  748.                         /* this shouldn't happen */
  749.                         if (debugflag)
  750.                         {
  751.                            static FCODE msg[] = {"debug, normal vector err2"};
  752.                            stopmsg(0, msg);
  753.                            /* use next instead if you ever need details:
  754.                             * static char far tmp[] = {"debug, vector err"};
  755.                             * char msg[200]; #ifndef XFRACT
  756.                             * sprintf(msg,"%Fs\n%f %f %f\n%f %f %f\n%f %f
  757.                             * %f", #else sprintf(msg,"%s\n%f %f %f\n%f %f
  758.                             * %f\n%f %f %f", #endif tmp, f_cur.x, f_cur.y,
  759.                             * f_cur.color, f_lastrow[col].x,
  760.                             * f_lastrow[col].y, f_lastrow[col].color,
  761.                             * f_lastrow[col-1].x,
  762.                             * f_lastrow[col-1].y,f_lastrow[col-1].color);
  763.                             * stopmsg(0,msg); */
  764.                         }
  765.                         cur.color = (int)(f_cur.color = colors);
  766.                      }
  767.                   }
  768.                   crossavg[0] = tmpcross[0];
  769.                   crossavg[1] = tmpcross[1];
  770.                   crossavg[2] = tmpcross[2];
  771.  
  772.                   /* dot product of unit vectors is cos of angle between */
  773.                   /* we will use this value to shade surface */
  774.  
  775.                   cur.color = (int) (1 + (colors - 2) *
  776.                                (1.0 - dot_product(cross, light_direction)));
  777.                }
  778.                /* if colors out of range, set them to min or max color index
  779.                 * but avoid background index. This makes colors "opaque" so
  780.                 * SOMETHING plots. These conditions shouldn't happen but just
  781.                 * in case                                        */
  782.                if (cur.color < 1)       /* prevent transparent colors */
  783.                   cur.color = 1;/* avoid background */
  784.                if (cur.color > colors - 1)
  785.                   cur.color = colors - 1;
  786.  
  787.                /* why "col < 2"? So we have sufficient geometry for the fill */
  788.                /* algorithm, which needs previous point in same row to have  */
  789.                /* already been calculated (variable old)                 */
  790.                /* fix ragged left margin in preview */
  791.                if (col == 1 && currow > 1)
  792.                   putatriangle(lastrow[next], lastrow[col], cur, cur.color);
  793.  
  794.                if (col < 2 || currow < 2)       /* don't have valid colors
  795.                                                  * yet */
  796.                   break;
  797.  
  798.                if (col < lastdot)
  799.                   putatriangle(lastrow[next], lastrow[col], cur, cur.color);
  800.                putatriangle(old, lastrow[col], cur, cur.color);
  801.  
  802.                plot = standardplot;
  803.             }
  804.             break;
  805.          }                      /* End of CASE statement for fill type  */
  806.        loopbottom:
  807.          if (RAY || (FILLTYPE != 0 && FILLTYPE != 4))
  808.          {
  809.             /* for triangle and grid fill purposes */
  810.             oldlast = lastrow[col];
  811.             old = lastrow[col] = cur;
  812.  
  813.             /* for illumination model purposes */
  814.             f_old = f_lastrow[col] = f_cur;
  815.             if (currow && RAY && col >= lastdot)
  816.                /* if we're at the end of a row, close the object */
  817.             {
  818.                end_object(tout);
  819.                tout = 0;
  820.                if (ferror(File_Ptr1))
  821.                {
  822.                   fclose(File_Ptr1);
  823.                   remove(light_name);
  824.                   File_Error(ray_name, 2);
  825.                   return (-1);
  826.                }
  827.             }
  828.          }
  829.          col++;
  830.       }                         /* End of while statement for plotting line  */
  831.    RO++;
  832.  reallythebottom:
  833.  
  834.    /* stuff that HAS to be done, even in preview mode, goes here */
  835.    if (SPHERE)
  836.    {
  837.       /* incremental sin/cos phi calc */
  838.       if (currow == 0)
  839.       {
  840.          sinphi = oldsinphi2;
  841.          cosphi = oldcosphi2;
  842.       }
  843.       else
  844.       {
  845.          sinphi = twocosdeltaphi * oldsinphi2 - oldsinphi1;
  846.          cosphi = twocosdeltaphi * oldcosphi2 - oldcosphi1;
  847.          oldsinphi1 = oldsinphi2;
  848.          oldsinphi2 = sinphi;
  849.          oldcosphi1 = oldcosphi2;
  850.          oldcosphi2 = cosphi;
  851.       }
  852.    }
  853.    return (0);                  /* decoder needs to know all is well !!! */
  854. }
  855.  
  856. /* vector version of line draw */
  857. static void _fastcall vdraw_line(double *v1, double *v2, int color)
  858. {
  859.    int x1, y1, x2, y2;
  860.    x1 = (int) v1[0];
  861.    y1 = (int) v1[1];
  862.    x2 = (int) v2[0];
  863.    y2 = (int) v2[1];
  864.    draw_line(x1, y1, x2, y2, color);
  865. }
  866.  
  867. static void corners(MATRIX m, int show, double *pxmin, double *pymin, double *pzmin, double *pxmax, double *pymax, double *pzmax)
  868. {
  869.    int i, j;
  870.    VECTOR S[2][4];              /* Holds the top an bottom points,
  871.                                  * S[0][]=bottom */
  872.  
  873.    /* define corners of box fractal is in in x,y,z plane "b" stands for
  874.     * "bottom" - these points are the corners of the screen in the x-y plane.
  875.     * The "t"'s stand for Top - they are the top of the cube where 255 color
  876.     * points hit. */
  877.  
  878.    *pxmin = *pymin = *pzmin = (int) INT_MAX;
  879.    *pxmax = *pymax = *pzmax = (int) INT_MIN;
  880.  
  881.    for (j = 0; j < 4; ++j)
  882.       for (i = 0; i < 3; i++)
  883.          S[0][j][i] = S[1][j][i] = 0;
  884.  
  885.    S[0][1][0] = S[0][2][0] = S[1][1][0] = S[1][2][0] = xdots - 1;
  886.    S[0][2][1] = S[0][3][1] = S[1][2][1] = S[1][3][1] = ydots - 1;
  887.    S[1][0][2] = S[1][1][2] = S[1][2][2] = S[1][3][2] = zcoord - 1;
  888.  
  889.    for (i = 0; i < 4; ++i)
  890.    {
  891.       /* transform points */
  892.       vmult(S[0][i], m, S[0][i]);
  893.       vmult(S[1][i], m, S[1][i]);
  894.  
  895.       /* update minimums and maximums */
  896.       if (S[0][i][0] <= *pxmin)
  897.          *pxmin = S[0][i][0];
  898.       if (S[0][i][0] >= *pxmax)
  899.          *pxmax = S[0][i][0];
  900.       if (S[1][i][0] <= *pxmin)
  901.          *pxmin = S[1][i][0];
  902.       if (S[1][i][0] >= *pxmax)
  903.          *pxmax = S[1][i][0];
  904.       if (S[0][i][1] <= *pymin)
  905.          *pymin = S[0][i][1];
  906.       if (S[0][i][1] >= *pymax)
  907.          *pymax = S[0][i][1];
  908.       if (S[1][i][1] <= *pymin)
  909.          *pymin = S[1][i][1];
  910.       if (S[1][i][1] >= *pymax)
  911.          *pymax = S[1][i][1];
  912.       if (S[0][i][2] <= *pzmin)
  913.          *pzmin = S[0][i][2];
  914.       if (S[0][i][2] >= *pzmax)
  915.          *pzmax = S[0][i][2];
  916.       if (S[1][i][2] <= *pzmin)
  917.          *pzmin = S[1][i][2];
  918.       if (S[1][i][2] >= *pzmax)
  919.          *pzmax = S[1][i][2];
  920.    }
  921.  
  922.    if (show)
  923.    {
  924.       if (persp)
  925.       {
  926.          for (i = 0; i < 4; i++)
  927.          {
  928.             perspective(S[0][i]);
  929.             perspective(S[1][i]);
  930.          }
  931.       }
  932.  
  933.       /* Keep the box surrounding the fractal */
  934.       for (j = 0; j < 2; j++)
  935.          for (i = 0; i < 4; ++i)
  936.          {
  937.             S[j][i][0] += xxadjust;
  938.             S[j][i][1] += yyadjust;
  939.          }
  940.  
  941.       draw_rect(S[0][0], S[0][1], S[0][2], S[0][3], 2, 1);      /* Bottom */
  942.  
  943.       draw_rect(S[0][0], S[1][0], S[0][1], S[1][1], 5, 0);      /* Sides */
  944.       draw_rect(S[0][2], S[1][2], S[0][3], S[1][3], 6, 0);
  945.  
  946.       draw_rect(S[1][0], S[1][1], S[1][2], S[1][3], 8, 1);      /* Top */
  947.    }
  948. }
  949.  
  950. /* This function draws a vector from origin[] to direct[] and a box
  951.         around it. The vector and box are transformed or not depending on
  952.         FILLTYPE.
  953. */
  954.  
  955. static void draw_light_box(double *origin, double *direct, MATRIX light_m)
  956. {
  957.    VECTOR S[2][4];
  958.    int i, j;
  959.    double temp;
  960.  
  961.    S[1][0][0] = S[0][0][0] = origin[0];
  962.    S[1][0][1] = S[0][0][1] = origin[1];
  963.  
  964.    S[1][0][2] = direct[2];
  965.  
  966.    for (i = 0; i < 2; i++)
  967.    {
  968.       S[i][1][0] = S[i][0][0];
  969.       S[i][1][1] = direct[1];
  970.       S[i][1][2] = S[i][0][2];
  971.       S[i][2][0] = direct[0];
  972.       S[i][2][1] = S[i][1][1];
  973.       S[i][2][2] = S[i][0][2];
  974.       S[i][3][0] = S[i][2][0];
  975.       S[i][3][1] = S[i][0][1];
  976.       S[i][3][2] = S[i][0][2];
  977.    }
  978.  
  979.    /* transform the corners if necessary */
  980.    if (FILLTYPE == 6)
  981.       for (i = 0; i < 4; i++)
  982.       {
  983.          vmult(S[0][i], light_m, S[0][i]);
  984.          vmult(S[1][i], light_m, S[1][i]);
  985.       }
  986.  
  987.    /* always use perspective to aid viewing */
  988.    temp = view[2];              /* save perspective distance for a later
  989.                                  * restore */
  990.    view[2] = -P * 300.0 / 100.0;
  991.  
  992.    for (i = 0; i < 4; i++)
  993.    {
  994.       perspective(S[0][i]);
  995.       perspective(S[1][i]);
  996.    }
  997.    view[2] = temp;              /* Restore perspective distance */
  998.  
  999.    /* Adjust for aspect */
  1000.    for (i = 0; i < 4; i++)
  1001.    {
  1002.       S[0][i][0] = S[0][i][0] * aspect;
  1003.       S[1][i][0] = S[1][i][0] * aspect;
  1004.    }
  1005.  
  1006.    /* draw box connecting transformed points. NOTE order and COLORS */
  1007.    draw_rect(S[0][0], S[0][1], S[0][2], S[0][3], 2, 1);
  1008.  
  1009.    vdraw_line(S[0][0], S[1][2], 8);
  1010.  
  1011.    /* sides */
  1012.    draw_rect(S[0][0], S[1][0], S[0][1], S[1][1], 4, 0);
  1013.    draw_rect(S[0][2], S[1][2], S[0][3], S[1][3], 5, 0);
  1014.  
  1015.    draw_rect(S[1][0], S[1][1], S[1][2], S[1][3], 3, 1);
  1016.  
  1017.    /* Draw the "arrow head" */
  1018.    for (i = -3; i < 4; i++)
  1019.       for (j = -3; j < 4; j++)
  1020.          if (abs(i) + abs(j) < 6)
  1021.             plot((int) (S[1][2][0] + i), (int) (S[1][2][1] + j), 10);
  1022. }
  1023.  
  1024. static void draw_rect(VECTOR V0, VECTOR V1, VECTOR V2, VECTOR V3, int color, int rect)
  1025. {
  1026.    VECTOR V[4];
  1027.    int i;
  1028.  
  1029.    /* Since V[2] is not used by vdraw_line don't bother setting it */
  1030.    for (i = 0; i < 2; i++)
  1031.    {                            
  1032.       V[0][i] = V0[i];
  1033.       V[1][i] = V1[i];
  1034.       V[2][i] = V2[i];
  1035.       V[3][i] = V3[i];
  1036.    }
  1037.    if (rect)                    /* Draw a rectangle */
  1038.    {
  1039.       for (i = 0; i < 4; i++)
  1040.          if (fabs(V[i][0] - V[(i + 1) % 4][0]) < -2 * bad_check &&
  1041.              fabs(V[i][1] - V[(i + 1) % 4][1]) < -2 * bad_check)
  1042.             vdraw_line(V[i], V[(i + 1) % 4], color);
  1043.    }
  1044.    else
  1045.       /* Draw 2 lines instead */
  1046.    {
  1047.       for (i = 0; i < 3; i += 2)
  1048.          if (fabs(V[i][0] - V[i + 1][0]) < -2 * bad_check &&
  1049.              fabs(V[i][1] - V[i + 1][1]) < -2 * bad_check)
  1050.             vdraw_line(V[i], V[i + 1], color);
  1051.    }
  1052.    return;
  1053. }
  1054.  
  1055. /* replacement for plot - builds a table of min and max x's instead of plot */
  1056. /* called by draw_line as part of triangle fill routine */
  1057. static void _fastcall putminmax(int x, int y, int color)
  1058. {
  1059.    color = 0; /* to supress warning only */
  1060.    if (y >= 0 && y < ydots)
  1061.    {
  1062.       if (x < minmax_x[y].minx)
  1063.          minmax_x[y].minx = x;
  1064.       if (x > minmax_x[y].maxx)
  1065.          minmax_x[y].maxx = x;
  1066.    }
  1067. }
  1068.  
  1069. /*
  1070.         This routine fills in a triangle. Extreme left and right values for
  1071.         each row are calculated by calling the line function for the sides.
  1072.         Then rows are filled in with horizontal lines
  1073. */
  1074. #define MAXOFFSCREEN  2    /* allow two of three points to be off screen */
  1075.  
  1076. static void _fastcall putatriangle(struct point pt1, struct point pt2, struct point pt3, int color)
  1077. {
  1078.    int miny, maxy;
  1079.    int x, y, xlim;
  1080.  
  1081.    /* Too many points off the screen? */
  1082.    if (offscreen(pt1) + offscreen(pt2) + offscreen(pt3) > MAXOFFSCREEN)
  1083.       return;
  1084.  
  1085.    p1 = pt1;                    /* needed by interpcolor */
  1086.    p2 = pt2;
  1087.    p3 = pt3;
  1088.  
  1089.    /* fast way if single point or single line */
  1090.    if (p1.y == p2.y && p1.x == p2.x)
  1091.    {
  1092.       plot = fillplot;
  1093.       if (p1.y == p3.y && p1.x == p3.x)
  1094.          (*plot) (p1.x, p1.y, color);
  1095.       else
  1096.          draw_line(p1.x, p1.y, p3.x, p3.y, color);
  1097.       plot = normalplot;
  1098.       return;
  1099.    }
  1100.    else if ((p3.y == p1.y && p3.x == p1.x) || (p3.y == p2.y && p3.x == p2.x))
  1101.    {
  1102.       plot = fillplot;
  1103.       draw_line(p1.x, p1.y, p2.x, p2.y, color);
  1104.       plot = normalplot;
  1105.       return;
  1106.    }
  1107.  
  1108.    /* find min max y */
  1109.    miny = maxy = p1.y;
  1110.    if (p2.y < miny)
  1111.       miny = p2.y;
  1112.    else
  1113.       maxy = p2.y;
  1114.    if (p3.y < miny)
  1115.       miny = p3.y;
  1116.    else if (p3.y > maxy)
  1117.       maxy = p3.y;
  1118.  
  1119.    /* only worried about values on screen */
  1120.    if (miny < 0)
  1121.       miny = 0;
  1122.    if (maxy >= ydots)
  1123.       maxy = ydots - 1;
  1124.  
  1125.    for (y = miny; y <= maxy; y++)
  1126.    {
  1127.       minmax_x[y].minx = (int) INT_MAX;
  1128.       minmax_x[y].maxx = (int) INT_MIN;
  1129.    }
  1130.  
  1131.    /* set plot to "fake" plot function */
  1132.    plot = putminmax;
  1133.  
  1134.    /* build table of extreme x's of triangle */
  1135.    draw_line(p1.x, p1.y, p2.x, p2.y, 0);
  1136.    draw_line(p2.x, p2.y, p3.x, p3.y, 0);
  1137.    draw_line(p3.x, p3.y, p1.x, p1.y, 0);
  1138.  
  1139.    for (y = miny; y <= maxy; y++)
  1140.    {
  1141.       xlim = minmax_x[y].maxx;
  1142.       for (x = minmax_x[y].minx; x <= xlim; x++)
  1143.          (*fillplot) (x, y, color);
  1144.    }
  1145.    plot = normalplot;
  1146. }
  1147.  
  1148. static int _fastcall offscreen(struct point pt)
  1149. {
  1150.    if (pt.x >= 0)
  1151.       if (pt.x < xdots)
  1152.          if (pt.y >= 0)
  1153.             if (pt.y < ydots)
  1154.                return (0);      /* point is ok */
  1155.    if (abs(pt.x) > 0 - bad_check || abs(pt.y) > 0 - bad_check)
  1156.       return (99);              /* point is bad */
  1157.    return (1);                  /* point is off the screen */
  1158. }
  1159.  
  1160. static void _fastcall clipcolor(int x, int y, int color)
  1161. {
  1162.    if (0 <= x && x < xdots &&
  1163.        0 <= y && y < ydots &&
  1164.        0 <= color && color < filecolors)
  1165.    {
  1166.       standardplot(x, y, color);
  1167.  
  1168.       if (Targa_Out)
  1169.          /* standardplot modifies color in these types */
  1170.          if (!(glassestype == 1 || glassestype == 2))   
  1171.             targa_color(x, y, color);
  1172.    }
  1173. }
  1174.  
  1175. /*********************************************************************/
  1176. /* This function is the same as clipcolor but checks for color being */
  1177. /* in transparent range. Intended to be called only if transparency  */
  1178. /* has been enabled.                                                 */
  1179. /*********************************************************************/
  1180.  
  1181. static void _fastcall T_clipcolor(int x, int y, int color)
  1182. {
  1183.    if (0 <= x && x < xdots &&   /* is the point on screen?  */
  1184.        0 <= y && y < ydots &&   /* Yes?  */
  1185.        0 <= color && color < colors &&  /* Colors in valid range?  */
  1186.    /* Lets make sure its not a transparent color  */
  1187.        (transparent[0] > color || color > transparent[1]))
  1188.    {
  1189.       standardplot(x, y, color);/* I guess we can plot then  */
  1190.       if (Targa_Out)
  1191.          /* standardplot modifies color in these types */
  1192.          if (!(glassestype == 1 || glassestype == 2))   
  1193.             targa_color(x, y, color);
  1194.    }
  1195. }
  1196.  
  1197. /************************************************************************/
  1198. /* A substitute for plotcolor that interpolates the colors according    */
  1199. /* to the x and y values of three points (p1,p2,p3) which are static in */
  1200. /* this routine                                                         */
  1201. /*                                                                      */
  1202. /*      In Light source modes, color is light value, not actual color   */
  1203. /*      Real_Color always contains the actual color                     */
  1204. /************************************************************************/
  1205.  
  1206. static void _fastcall interpcolor(int x, int y, int color)
  1207. {
  1208.    int D, d1, d2, d3;
  1209.  
  1210.    /* this distance formula is not the usual one - but it has the virtue that
  1211.     * it uses ONLY additions (almost) and it DOES go to zero as the points
  1212.     * get close. */
  1213.  
  1214.    d1 = abs(p1.x - x) + abs(p1.y - y);
  1215.    d2 = abs(p2.x - x) + abs(p2.y - y);
  1216.    d3 = abs(p3.x - x) + abs(p3.y - y);
  1217.  
  1218.    D = (d1 + d2 + d3) << 1;
  1219.    if (D)
  1220.    {  /* calculate a weighted average of colors long casts prevent integer 
  1221.          overflow. This can evaluate to zero */
  1222.       color = (int) (((long) (d2 + d3) * (long) p1.color +
  1223.                       (long) (d1 + d3) * (long) p2.color +
  1224.                       (long) (d1 + d2) * (long) p3.color) / D);
  1225.    }
  1226.  
  1227.    if (0 <= x && x < xdots &&
  1228.        0 <= y && y < ydots &&
  1229.        0 <= color && color < colors &&
  1230.        (transparent[1] == 0 || (int) Real_Color > transparent[1] ||
  1231.         transparent[0] > (int) Real_Color))
  1232.    {
  1233.       if (Targa_Out)
  1234.          /* standardplot modifies color in these types */
  1235.          if (!(glassestype == 1 || glassestype == 2))   
  1236.             D = targa_color(x, y, color);
  1237.  
  1238.       if (FILLTYPE >= 5)
  1239.          if (Real_V && Targa_Out)
  1240.             color = D;
  1241.          else
  1242.          {
  1243.             color = (1 + (unsigned) color * IAmbient) / 256;
  1244.             if (color == 0)
  1245.                color = 1;
  1246.          }
  1247.       standardplot(x, y, color);
  1248.    }
  1249. }
  1250.  
  1251. /*
  1252.         In non light source modes, both color and Real_Color contain the
  1253.         actual pixel color. In light source modes, color contains the
  1254.         light value, and Real_Color contains the origninal color
  1255.  
  1256.         This routine takes a pixel modifies it for lightshading if appropriate
  1257.         and plots it in a Targa file. Used in plot3d.c
  1258. */
  1259.  
  1260. int _fastcall targa_color(int x, int y, int color)
  1261. {
  1262.    unsigned long H, S, V;
  1263.    BYTE RGB[3];
  1264.  
  1265.    if (FILLTYPE == 2 || glassestype == 1 || glassestype == 2)
  1266.       Real_Color = (BYTE)color;       /* So Targa gets interpolated color */
  1267.  
  1268.    RGB[0] = (BYTE)(dacbox[Real_Color][0] << 2); /* Move color space to */
  1269.    RGB[1] = (BYTE)(dacbox[Real_Color][1] << 2); /* 256 color primaries */
  1270.    RGB[2] = (BYTE)(dacbox[Real_Color][2] << 2); /* from 64 colors */
  1271.  
  1272.    /* Now lets convert it to HSV */
  1273.    R_H(RGB[0], RGB[1], RGB[2], &H, &S, &V);
  1274.  
  1275.    /* Modify original S and V components */
  1276.    if (FILLTYPE > 4 && !(glassestype == 1 || glassestype == 2)) 
  1277.       /* Adjust for Ambient */
  1278.       V = (V * (65535L - (unsigned) (color * IAmbient))) / 65535L;
  1279.  
  1280.    if (haze)
  1281.    {
  1282.       /* Haze lowers sat of colors */
  1283.       S = (unsigned long) (S * HAZE_MULT) / 100;        
  1284.       if (V >= 32640)           /* Haze reduces contrast */
  1285.       {
  1286.          V = V - 32640;
  1287.          V = (unsigned long) ((V * HAZE_MULT) / 100);
  1288.          V = V + 32640;
  1289.       }
  1290.       else
  1291.       {
  1292.          V = 32640 - V;
  1293.          V = (unsigned long) ((V * HAZE_MULT) / 100);
  1294.          V = 32640 - V;
  1295.       }
  1296.    }
  1297.    /* Now lets convert it back to RGB. Original Hue, modified Sat and Val */
  1298.    H_R(&RGB[0], &RGB[1], &RGB[2], H, S, V);
  1299.  
  1300.    if (Real_V)
  1301.       V = (35 * (int) RGB[0] + 45 * (int) RGB[1] + 20 * (int) RGB[2]) / 100;
  1302.  
  1303.    /* Now write the color triple to its transformed location */
  1304.    /* on the disk. */
  1305.    targa_writedisk(x + sxoffs, y + syoffs, RGB[0], RGB[1], RGB[2]);
  1306.  
  1307.    return ((int) (255 - V));
  1308. }
  1309.  
  1310. static int set_pixel_buff(BYTE * pixels, BYTE far * fraction, unsigned linelen)
  1311. {
  1312.    int i;
  1313.    if ((evenoddrow++ & 1) == 0) /* even rows are color value */
  1314.    {
  1315.       for (i = 0; i < (int) linelen; i++)       /* add the fractional part in
  1316.                                                  * odd row */
  1317.          fraction[i] = pixels[i];
  1318.       return (1);
  1319.    }
  1320.    else
  1321.       /* swap */
  1322.    {
  1323.       BYTE tmp;
  1324.       for (i = 0; i < (int) linelen; i++)       /* swap so pixel has color */
  1325.       {
  1326.          tmp = pixels[i];
  1327.          pixels[i] = fraction[i];
  1328.          fraction[i] = tmp;
  1329.       }
  1330.    }
  1331.    return (0);
  1332. }
  1333.  
  1334. /**************************************************************************
  1335.  
  1336.   Common routine for printing error messages to the screen for Targa
  1337.     and other files
  1338.  
  1339. **************************************************************************/
  1340.  
  1341. #ifndef XFRACT
  1342. static char s_f[] = "%Fs%Fs";
  1343. static char s_fff[] = "%Fs%Fs%Fs";
  1344. #else
  1345. static char s_f[] = "%s%s";
  1346. static char s_fff[] = "%s%s%s";
  1347. #endif
  1348. static FCODE OOPS[] = {"OOPS, "};
  1349. static FCODE E1[] = {"can't handle this type of file.\n"};
  1350. static FCODE str1[] = {"couldn't open  < "};
  1351. static FCODE str3[] = {"image wrong size\n"};
  1352. static FCODE outofdisk[] = {"ran out of disk space. < "};
  1353.  
  1354. static void File_Error(char *File_Name1, int ERROR)
  1355. {
  1356.    char msgbuf[200];
  1357.  
  1358.    error = ERROR;
  1359.    switch (ERROR)
  1360.    {
  1361.    case 1:                      /* Can't Open */
  1362. #ifndef XFRACT
  1363.       sprintf(msgbuf, "%Fs%Fs%s >", (char far *)OOPS, (char far *)str1, File_Name1);
  1364. #else
  1365.       sprintf(msgbuf, "%s%s%s >", OOPS, str1, File_Name1);
  1366. #endif
  1367.       break;
  1368.    case 2:                      /* Not enough room */
  1369. #ifndef XFRACT
  1370.       sprintf(msgbuf, "%Fs%Fs%s >", (char far *)OOPS, (char far *)outofdisk, File_Name1);
  1371. #else
  1372.       sprintf(msgbuf, "%s%s%s >", OOPS, outofdisk, File_Name1);
  1373. #endif
  1374.       break;
  1375.    case 3:                      /* Image wrong size */
  1376.       sprintf(msgbuf, s_f, (char far *)OOPS, (char far *)str3);
  1377.       break;
  1378.    case 4:                      /* Wrong file type */
  1379.       sprintf(msgbuf, s_f, (char far *)OOPS, (char far *)E1);
  1380.       break;
  1381.    }
  1382.    stopmsg(0, msgbuf);
  1383.    return;
  1384. }
  1385.  
  1386.  
  1387. /************************************************************************/
  1388. /*                                                                      */
  1389. /*   This function opens a TARGA_24 file for reading and writing. If    */
  1390. /*   its a new file, (overlay == 0) it writes a header. If it is to     */
  1391. /*   overlay an existing file (overlay == 1) it copies the original     */
  1392. /*   header whose lenght and validity was determined in                 */
  1393. /*   Targa_validate.                                                    */
  1394. /*                                                                      */
  1395. /*   It Verifies there is enough disk space, and leaves the file        */
  1396. /*   at the start of the display data area.                             */
  1397. /*                                                                      */
  1398. /*   If this is an overlay, closes source and copies to "targa_temp"    */
  1399. /*   If there is an error close the file.                               */
  1400. /*                                                                      */
  1401. /* **********************************************************************/
  1402.  
  1403.  
  1404. static int startdisk1(char *File_Name2, FILE * Source, int overlay)
  1405. {
  1406.    int i, j, k, inc;
  1407.    FILE *fps;
  1408.  
  1409.    /* Open File for both reading and writing */
  1410.    if ((fps = dir_fopen(tempdir,File_Name2, "w+b")) == NULL)
  1411.    {
  1412.       File_Error(File_Name2, 1);
  1413.       return (-1);              /* Oops, somethings wrong! */
  1414.    }
  1415.  
  1416.    inc = 1;                     /* Assume we are overlaying a file */
  1417.  
  1418.    /* Write the header */
  1419.    if (overlay)                 /* We are overlaying a file */
  1420.       for (i = 0; i < T_header_24; i++) /* Copy the header from the Source */
  1421.          fputc(fgetc(Source), fps);
  1422.    else
  1423.    {                            /* Write header for a new file */
  1424.       /* ID field size = 0, No color map, Targa type 2 file */
  1425.       for (i = 0; i < 12; i++)
  1426.       {
  1427.          if (i == 2)
  1428.             fputc(i, fps);
  1429.          else
  1430.             fputc(0, fps);
  1431.       }
  1432.       /* Write image size  */
  1433.       for (i = 0; i < 4; i++)
  1434.          fputc(upr_lwr[i], fps);
  1435.       fputc(T24, fps);          /* Targa 24 file */
  1436.       fputc(T32, fps);          /* Image at upper left */
  1437.       inc = 3;
  1438.    }
  1439.  
  1440.    /* Finished with the header, now lets work on the display area  */
  1441.    for (i = 0; i < ydots; i++)  /* "clear the screen" (write to the disk) */
  1442.    {
  1443.       for (j = 0; j < line_length1; j = j + inc)
  1444.       {
  1445.          if (overlay)
  1446.             fputc(fgetc(Source), fps);
  1447.          else
  1448.             for (k = 2; k > -1; k--)
  1449.                fputc(back_color[k], fps);       /* Targa order (B, G, R) */
  1450.       }
  1451.       if (ferror(fps))
  1452.       {
  1453.          /* Almost certainly not enough disk space  */
  1454.          fclose(fps);
  1455.          fclose(Source);
  1456.          dir_remove(tempdir,File_Name2);
  1457.          File_Error(File_Name2, 2);
  1458.          return (-2);
  1459.       }
  1460.       if (keypressed())
  1461.          return (-3);
  1462.    }
  1463.  
  1464.    if (targa_startdisk(fps, T_header_24) != 0)
  1465.    {
  1466.       enddisk();
  1467.       dir_remove(tempdir,File_Name2);
  1468.       return (-4);
  1469.    }
  1470.    return (0);
  1471. }
  1472.  
  1473. int targa_validate(char *File_Name)
  1474. {
  1475.    FILE *fp;
  1476.    int i;
  1477. #if 0
  1478.    int j = 0;
  1479. #endif
  1480.  
  1481.    /* Attempt to open source file for reading */
  1482.    if ((fp = fopen(File_Name, "rb")) == NULL)
  1483.    {
  1484.       File_Error(File_Name, 1);
  1485.       return (-1);              /* Oops, file does not exist */
  1486.    }
  1487.  
  1488.    T_header_24 += fgetc(fp);    /* Check ID field and adjust header size */
  1489.  
  1490.    if (fgetc(fp))               /* Make sure this is an unmapped file */
  1491.    {
  1492.       File_Error(File_Name, 4);
  1493.       return (-1);
  1494.    }
  1495.  
  1496.    if (fgetc(fp) != 2)          /* Make sure it is a type 2 file */
  1497.    {
  1498.       File_Error(File_Name, 4);
  1499.       return (-1);
  1500.    }
  1501.  
  1502.    /* Skip color map specification */
  1503.    for (i = 0; i < 5; i++)
  1504.       fgetc(fp);
  1505.  
  1506.    for (i = 0; i < 4; i++)
  1507.    {
  1508.       /* Check image origin */
  1509.       fgetc(fp);
  1510. #if 0
  1511.       if (j != 0)
  1512.       {
  1513.          File_Error(File_Name, 4);
  1514.          return (-1);
  1515.       }
  1516. #endif
  1517.    }
  1518.    /* Check Image specs */
  1519.    for (i = 0; i < 4; i++)
  1520.       if (fgetc(fp) != (int) upr_lwr[i])
  1521.       {
  1522.          File_Error(File_Name, 3);
  1523.          return (-1);
  1524.       }
  1525.  
  1526.    if (fgetc(fp) != (int) T24)
  1527.       error = 4;                /* Is it a targa 24 file? */
  1528.    if (fgetc(fp) != (int) T32)
  1529.       error = 4;                /* Is the origin at the upper left? */
  1530.    if (error == 4)
  1531.    {
  1532.       File_Error(File_Name, 4);
  1533.       return (-1);
  1534.    }
  1535.    rewind(fp);
  1536.  
  1537.    /* Now that we know its a good file, create a working copy */
  1538.    if (startdisk1(targa_temp, fp, 1))
  1539.       return (-1);
  1540.  
  1541.    fclose(fp);                  /* Close the source */
  1542.  
  1543.    T_Safe = 1;                  /* Original file successfully copied to
  1544.                                  * targa_temp */
  1545.    return (0);
  1546. }
  1547.  
  1548. static int R_H(BYTE R, BYTE G, BYTE B, unsigned long *H, unsigned long *S, unsigned long *V)
  1549. {
  1550.    unsigned long R1, G1, B1, DENOM;
  1551.    BYTE MIN;
  1552.  
  1553.    *V = R;
  1554.    MIN = G;
  1555.    if (R < G)
  1556.    {
  1557.       *V = G;
  1558.       MIN = R;
  1559.       if (G < B)
  1560.          *V = B;
  1561.       if (B < R)
  1562.          MIN = B;
  1563.    }
  1564.    else
  1565.    {
  1566.       if (B < G)
  1567.          MIN = B;
  1568.       if (R < B)
  1569.          *V = B;
  1570.    }
  1571.    DENOM = *V - MIN;
  1572.    if (*V != 0 && DENOM != 0)
  1573.    {
  1574.       *S = ((DENOM << 16) / *V) - 1;
  1575.    }
  1576.    else
  1577.       *S = 0;      /* Color is black! and Sat has no meaning */
  1578.    if (*S == 0)    /* R=G=B => shade of grey and Hue has no meaning */
  1579.    {
  1580.       *H = 0;
  1581.       *V = *V << 8;
  1582.       return (1);               /* v or s or both are 0 */
  1583.    }
  1584.    if (*V == MIN)
  1585.    {
  1586.       *H = 0;
  1587.       *V = *V << 8;
  1588.       return (0);
  1589.    }
  1590.    R1 = (((*V - R) * 60) << 6) / DENOM; /* distance of color from red   */
  1591.    G1 = (((*V - G) * 60) << 6) / DENOM; /* distance of color from green */
  1592.    B1 = (((*V - B) * 60) << 6) / DENOM; /* distance of color from blue  */
  1593.    if (*V == R)
  1594.       if (MIN == G)
  1595.          *H = (300 << 6) + B1;
  1596.       else
  1597.          *H = (60 << 6) - G1;
  1598.    if (*V == G)
  1599.       if (MIN == B)
  1600.          *H = (60 << 6) + R1;
  1601.       else
  1602.          *H = (180 << 6) - B1;
  1603.    if (*V == B)
  1604.       if (MIN == R)
  1605.          *H = (180 << 6) + G1;
  1606.       else
  1607.          *H = (300 << 6) - R1;
  1608.  
  1609.    *V = *V << 8;
  1610.    return (0);
  1611. }
  1612.  
  1613. static int H_R(BYTE *R, BYTE *G, BYTE *B, unsigned long H, unsigned long S, unsigned long V)
  1614. {
  1615.    unsigned long P1, P2, P3;
  1616.    int RMD, I;
  1617.  
  1618.    if (H >= 23040)
  1619.       H = H % 23040;            /* Makes h circular  */
  1620.    I = (int) (H / 3840);
  1621.    RMD = (int) (H % 3840);      /* RMD = fractional part of H    */
  1622.  
  1623.    P1 = ((V * (65535L - S)) / 65280L) >> 8;
  1624.    P2 = (((V * (65535L - (S * RMD) / 3840)) / 65280L) - 1) >> 8;
  1625.    P3 = (((V * (65535L - (S * (3840 - RMD)) / 3840)) / 65280L)) >> 8;
  1626.    V = V >> 8;
  1627.    switch (I)
  1628.    {
  1629.    case 0:
  1630.       *R = (BYTE) V;
  1631.       *G = (BYTE) P3;
  1632.       *B = (BYTE) P1;
  1633.       break;
  1634.    case 1:
  1635.       *R = (BYTE) P2;
  1636.       *G = (BYTE) V;
  1637.       *B = (BYTE) P1;
  1638.       break;
  1639.    case 2:
  1640.       *R = (BYTE) P1;
  1641.       *G = (BYTE) V;
  1642.       *B = (BYTE) P3;
  1643.       break;
  1644.    case 3:
  1645.       *R = (BYTE) P1;
  1646.       *G = (BYTE) P2;
  1647.       *B = (BYTE) V;
  1648.       break;
  1649.    case 4:
  1650.       *R = (BYTE) P3;
  1651.       *G = (BYTE) P1;
  1652.       *B = (BYTE) V;
  1653.       break;
  1654.    case 5:
  1655.       *R = (BYTE) V;
  1656.       *G = (BYTE) P1;
  1657.       *B = (BYTE) P2;
  1658.       break;
  1659.    }
  1660.    return (0);
  1661. }
  1662.  
  1663.  
  1664. /***************************************************************************/
  1665. /*                                                                         */
  1666. /* EB & DG fiddled with outputs for Rayshade so they work. with v4.x.      */
  1667. /* EB == eli brandt.     ebrandt@jarthur.claremont.edu                     */
  1668. /* DG == dan goldwater.  daniel_goldwater@brown.edu & dgold@math.umass.edu */
  1669. /*  (NOTE: all the stuff we fiddled with is commented with "EB & DG" )     */
  1670. /* general raytracing code info/notes:                                     */
  1671. /*                                                                         */
  1672. /*  ray == 0 means no raytracer output  ray == 7 is for dxf                */
  1673. /*  ray == 1 is for dkb/pov             ray == 4 is for mtv                */
  1674. /*  ray == 2 is for vivid               ray == 5 is for rayshade           */
  1675. /*  ray == 3 is for raw                 ray == 6 is for acrospin           */
  1676. /*                                                                         */
  1677. /*  rayshade needs counterclockwise triangles.  raytracers that support    */
  1678. /*  the 'heightfield' primitive include rayshade and pov.  anyone want to  */
  1679. /*  write code to make heightfields?  they are *MUCH* faster to trace than */
  1680. /*  triangles when doing landscapes...                                     */
  1681. /*                                                                         */
  1682. /*  stuff EB & DG changed:                                                 */
  1683. /*  made the rayshade output create a "grid" aggregate object (one of      */
  1684. /*  rayshade's primitives), instead  of a global grid.  as a result, the   */
  1685. /*  grid can be optimized based on the number of triangles.                */
  1686. /*  the z component of the grid can always be 1 since the surface formed   */
  1687. /*  by the triangles is flat                                               */
  1688. /*  (ie, it doesnt curve over itself).  this is a major optimization.      */
  1689. /*  the x and y grid size is also optimized for a 4:3 aspect ratio image,  */
  1690. /*  to get the fewest possible traingles in each grid square.              */
  1691. /*  also, we fixed the rayshade code so it actually produces output that   */
  1692. /*  works with rayshade.                                                   */
  1693. /*  (maybe the old code was for a really old version of rayshade?).        */
  1694. /*                                                                         */
  1695. /***************************************************************************/
  1696.  
  1697. /********************************************************************/
  1698. /*                                                                  */
  1699. /*  This routine writes a header to a ray tracer data file. It      */
  1700. /*  Identifies the version of FRACTINT which created it an the      */
  1701. /*  key 3D parameters in effect at the time.                        */
  1702. /*                                                                  */
  1703. /********************************************************************/
  1704.  
  1705. static FCODE declare[] = {"DECLARE       "};
  1706. static FCODE frac_default[] = {"F_Dflt"};
  1707. static FCODE s_color[] = {"COLOR  "};
  1708. static FCODE dflt[] = {"RED 0.8 GREEN 0.4 BLUE 0.1\n"};
  1709. static FCODE d_color[] = {"0.8 0.4 0.1"};
  1710. static FCODE r_surf[] = {"0.95 0.05 5 0 0\n"};
  1711. static FCODE surf[] = {"surf={diff="};
  1712. /* EB & DG: changed "surface T" to "applysurf" and "diff" to "diffuse" */
  1713. static FCODE rs_surf[] = {"applysurf diffuse "}; 
  1714. static FCODE end[] = {"END_"};
  1715. static FCODE plane[] = {"PLANE"};
  1716. static FCODE m1[] = {"-1.0 "};
  1717. static FCODE one[] = {" 1.0 "};
  1718. static FCODE z[] = {" 0.0 "};
  1719. static FCODE bnd_by[] = {" BOUNDED_BY\n"};
  1720. static FCODE end_bnd[] = {" END_BOUND\n"};
  1721. static FCODE inter[] = {"INTERSECTION\n"};
  1722. #ifndef XFRACT
  1723. static char fmt[] = "   %Fs <%Fs%Fs%Fs> % #4.3f %Fs%Fs\n";
  1724. #else
  1725. static char fmt[] = "   %s <%s%s%s> % #4.3f %s%s\n";
  1726. #endif
  1727. static char dxf_begin[] =
  1728. {"  0\nSECTION\n  2\nTABLES\n  0\nTABLE\n  2\nLAYER\n\
  1729.  70\n     2\n  0\nLAYER\n  2\n0\n 70\n     0\n 62\n     7\n  6\nCONTINUOUS\n\
  1730.   0\nLAYER\n  2\nFRACTAL\n 70\n    64\n 62\n     1\n  6\nCONTINUOUS\n  0\n\
  1731. ENDTAB\n  0\nENDSEC\n  0\nSECTION\n  2\nENTITIES\n"};
  1732. static char dxf_3dface[] = {"  0\n3DFACE\n  8\nFRACTAL\n 62\n%3d\n"};
  1733. static char dxf_vertex[] = {"%3d\n%g\n"};
  1734. static char dxf_end[] = {"  0\nENDSEC\n  0\nEOF\n"};
  1735. static FCODE composite[] = {"COMPOSITE"};
  1736. static FCODE object[] = {"OBJECT"};
  1737. static FCODE triangle[] = {"TRIANGLE "};
  1738. static FCODE l_tri[] = {"triangle"};
  1739. static FCODE texture[] = {"TEXTURE\n"};
  1740. /* static FCODE end_texture[] = {" END_TEXTURE\n"}; */
  1741. static FCODE red[] = {"RED"};
  1742. static FCODE green[] = {"GREEN"};
  1743. static FCODE blue[] = {"BLUE"};
  1744. static FCODE frac_texture[] = {"      AMBIENT 0.25 DIFFUSE 0.75"};
  1745. static FCODE polygon[] = {"polygon={points=3;"};
  1746. static FCODE vertex[] = {" vertex =  "};
  1747. static FCODE d_vert[] = {"      <"};
  1748. static char f1[] = "% #4.4f ";
  1749. /* EB & DG: changed this to much better values */
  1750. static FCODE grid[] =
  1751. {"screen 640 480\neyep 0 2.1 0.8\nlookp 0 0 -0.95\nlight 1 point -2 1 1.5\n"};
  1752. static FCODE grid2[] = {"background .3 0 0\nreport verbose\n"};
  1753.  
  1754. static char s_n[] = "\n";
  1755. static char f2[] = "R%dC%d R%dC%d\n";
  1756. static FCODE ray_comment1[] =
  1757.    {"/* make a gridded aggregate. this size grid is fast for landscapes. */\n"};
  1758. static FCODE ray_comment2[] = 
  1759.    {"/* make z grid = 1 always for landscapes. */\n\n"};
  1760. static FCODE grid3[] = {"grid 33 25 1\n"};
  1761.  
  1762. static int _fastcall RAY_Header(void)
  1763. {  
  1764.    /* Open the ray tracing output file */
  1765.    check_writefile(ray_name, ".ray");
  1766.    if ((File_Ptr1 = fopen(ray_name, "w")) == NULL)
  1767.       return (-1);              /* Oops, somethings wrong! */
  1768.  
  1769.    if (RAY == 2)
  1770.       fprintf(File_Ptr1, "//");
  1771.    if (RAY == 4)
  1772.       fprintf(File_Ptr1, "#");
  1773.    if (RAY == 5)
  1774.       fprintf(File_Ptr1, "/*\n");
  1775.    if (RAY == 6)
  1776.       fprintf(File_Ptr1, "--");
  1777.    if (RAY == 7)
  1778.       fprintf(File_Ptr1, dxf_begin);
  1779.  
  1780.    if (RAY != 7)
  1781.       fprintf(File_Ptr1, banner, (char far *)s3, release / 100., (char far *)s3a);
  1782.  
  1783.    if (RAY == 5)
  1784.       fprintf(File_Ptr1, "*/\n");
  1785.  
  1786.  
  1787.    /* Set the default color */
  1788.    if (RAY == 1)
  1789.    {
  1790.       fprintf(File_Ptr1, s_f, (char far *)declare, (char far *)frac_default);
  1791.       fprintf(File_Ptr1, " = ");
  1792.       fprintf(File_Ptr1, s_f, (char far *)s_color, (char far *)dflt);
  1793.    }
  1794.    if (BRIEF)
  1795.    {
  1796.       if (RAY == 2)
  1797.       {
  1798.          fprintf(File_Ptr1, s_f, (char far *)surf, (char far *)d_color);
  1799.          fprintf(File_Ptr1, ";}\n");
  1800.       }
  1801.       if (RAY == 4)
  1802.       {
  1803.          fprintf(File_Ptr1, "f ");
  1804.          fprintf(File_Ptr1, s_f, (char far *)d_color, (char far *)r_surf);
  1805.       }
  1806.       if (RAY == 5)
  1807.          fprintf(File_Ptr1, s_f, (char far *)rs_surf, (char far *)d_color);
  1808.    }
  1809.    if (RAY != 7)
  1810.       fprintf(File_Ptr1, s_n);
  1811.  
  1812.    /* EB & DG: open "grid" opject, a speedy way to do aggregates in rayshade */
  1813.    if (RAY == 5) 
  1814.       fprintf(File_Ptr1, s_fff, (char far *)ray_comment1, (char far *)ray_comment2, (char far *)grid3);
  1815.  
  1816.    if (RAY == 6)
  1817. #ifndef XFRACT
  1818.       fprintf(File_Ptr1, "%Fs", (char far *)acro_s1);
  1819. #else
  1820.       fprintf(File_Ptr1, "%s", acro_s1);
  1821. #endif
  1822.  
  1823.    return (0);
  1824. }
  1825.  
  1826.  
  1827. /********************************************************************/
  1828. /*                                                                  */
  1829. /*  This routine describes the triangle to the ray tracer, it       */
  1830. /*  sets the color of the triangle to the average of the color      */
  1831. /*  of its verticies and sets the light parameters to arbitrary     */
  1832. /*  values.                                                         */
  1833. /*                                                                  */
  1834. /*  Note: numcolors (number of colors in the source                 */
  1835. /*  file) is used instead of colors (number of colors avail. with   */
  1836. /*  display) so you can generate ray trace files with your LCD      */
  1837. /*  or monochrome display                                           */
  1838. /*                                                                  */
  1839. /********************************************************************/
  1840.  
  1841. static int _fastcall out_triangle(struct f_point pt1, struct f_point pt2, struct f_point pt3, int c1, int c2, int c3)
  1842. {
  1843.    int i, j;
  1844.    float c[3];
  1845.    float pt_t[3][3];
  1846.  
  1847.    /* Normalize each vertex to screen size and adjust coordinate system */
  1848.    pt_t[0][0] = 2 * pt1.x / xdots - 1;
  1849.    pt_t[0][1] = (2 * pt1.y / ydots - 1);
  1850.    pt_t[0][2] = -2 * pt1.color / numcolors - 1;
  1851.    pt_t[1][0] = 2 * pt2.x / xdots - 1;
  1852.    pt_t[1][1] = (2 * pt2.y / ydots - 1);
  1853.    pt_t[1][2] = -2 * pt2.color / numcolors - 1;
  1854.    pt_t[2][0] = 2 * pt3.x / xdots - 1;
  1855.    pt_t[2][1] = (2 * pt3.y / ydots - 1);
  1856.    pt_t[2][2] = -2 * pt3.color / numcolors - 1;
  1857.  
  1858.    /* Color of triangle is average of colors of its verticies */
  1859.    if (!BRIEF)
  1860.       for (i = 0; i <= 2; i++)
  1861.          c[i] = (float) (dacbox[c1][i] + dacbox[c2][i] + dacbox[c3][i])
  1862.             / (3 * 63);
  1863.  
  1864.    /* get rid of degenerate triangles: any two points equal */
  1865.    if ((pt_t[0][0] == pt_t[1][0] &&
  1866.         pt_t[0][1] == pt_t[1][1] &&
  1867.         pt_t[0][2] == pt_t[1][2]) ||
  1868.  
  1869.        (pt_t[0][0] == pt_t[2][0] &&
  1870.         pt_t[0][1] == pt_t[2][1] &&
  1871.         pt_t[0][2] == pt_t[2][2]) ||
  1872.  
  1873.        (pt_t[2][0] == pt_t[1][0] &&
  1874.         pt_t[2][1] == pt_t[1][1] &&
  1875.         pt_t[2][2] == pt_t[1][2]))
  1876.       return (0);
  1877.  
  1878.    /* Describe the triangle */
  1879. #ifndef XFRACT
  1880.    if (RAY == 1)
  1881.       fprintf(File_Ptr1, " %Fs\n  %Fs", (char far *)object, (char far *)triangle);
  1882.    if (RAY == 2 && !BRIEF)
  1883.       fprintf(File_Ptr1, "%Fs", (char far *)surf);
  1884. #else
  1885.    if (RAY == 1)
  1886.       fprintf(File_Ptr1, " %s\n  %s", object, triangle);
  1887.    if (RAY == 2 && !BRIEF)
  1888.       fprintf(File_Ptr1, "%s", surf);
  1889. #endif
  1890.    if (RAY == 4 && !BRIEF)
  1891.       fprintf(File_Ptr1, "f");
  1892.    if (RAY == 5 && !BRIEF)
  1893. #ifndef XFRACT
  1894.       fprintf(File_Ptr1, "%Fs", (char far *)rs_surf);
  1895. #else
  1896.       fprintf(File_Ptr1, "%s", rs_surf);
  1897. #endif
  1898.  
  1899.    if (!BRIEF && RAY != 1 && RAY != 7)
  1900.       for (i = 0; i <= 2; i++)
  1901.          fprintf(File_Ptr1, f1, c[i]);
  1902.  
  1903.    if (RAY == 2)
  1904.    {
  1905.       if (!BRIEF)
  1906.          fprintf(File_Ptr1, ";}\n");
  1907. #ifndef XFRACT
  1908.       fprintf(File_Ptr1, "%Fs", (char far *)polygon);
  1909. #else
  1910.       fprintf(File_Ptr1, "%s", polygon);
  1911. #endif
  1912.    }
  1913.    if (RAY == 4)
  1914.    {
  1915.       if (!BRIEF)
  1916. #ifndef XFRACT
  1917.          fprintf(File_Ptr1, "%Fs", (char far *)r_surf);
  1918. #else
  1919.          fprintf(File_Ptr1, "%s", r_surf);
  1920. #endif
  1921.       fprintf(File_Ptr1, "p 3");
  1922.    }
  1923.    if (RAY == 5)
  1924.    {
  1925.       if (!BRIEF)
  1926.          fprintf(File_Ptr1, s_n);
  1927.       /* EB & DG: removed "T" after "triangle" */
  1928. #ifndef XFRACT
  1929.       fprintf(File_Ptr1, "%Fs", (char far *)l_tri); 
  1930. #else
  1931.       fprintf(File_Ptr1, "%s", l_tri);  
  1932. #endif
  1933.    }
  1934.  
  1935.    if (RAY == 7)
  1936.       fprintf(File_Ptr1, dxf_3dface, min(255, max(1, c1)));
  1937.  
  1938.    for (i = 0; i <= 2; i++)     /* Describe each  Vertex  */
  1939.    {
  1940.       if (RAY != 7)
  1941.          fprintf(File_Ptr1, s_n);
  1942.  
  1943. #ifndef XFRACT
  1944.       if (RAY == 1)
  1945.          fprintf(File_Ptr1, "%Fs", (char far *)d_vert);
  1946.       if (RAY == 2)
  1947.          fprintf(File_Ptr1, "%Fs", (char far *)vertex);
  1948. #else
  1949.       if (RAY == 1)
  1950.          fprintf(File_Ptr1, "%s", d_vert);
  1951.       if (RAY == 2)
  1952.          fprintf(File_Ptr1, "%s", vertex);
  1953. #endif
  1954.       if (RAY > 3 && RAY != 7)
  1955.          fprintf(File_Ptr1, " ");
  1956.  
  1957.       for (j = 0; j <= 2; j++)
  1958.       {
  1959.          if (RAY == 7)
  1960.          {
  1961.             /* write 3dface entity to dxf file */
  1962.             fprintf(File_Ptr1, dxf_vertex, 10 * (j + 1) + i, pt_t[i][j]);
  1963.             if (i == 2)         /* 3dface needs 4 vertecies */
  1964.                fprintf(File_Ptr1, dxf_vertex, 10 * (j + 1) + i + 1, 
  1965.                   pt_t[i][j]);
  1966.          }
  1967.          else if (!(RAY == 4 || RAY == 5))
  1968.             fprintf(File_Ptr1, f1, pt_t[i][j]); /* Right handed */
  1969.          else
  1970.             fprintf(File_Ptr1, f1, pt_t[2 - i][j]);     /* Left handed */
  1971.       }
  1972.  
  1973.       if (RAY == 1)
  1974.          fprintf(File_Ptr1, ">");
  1975.       if (RAY == 2)
  1976.          fprintf(File_Ptr1, ";");
  1977.    }
  1978.  
  1979.    if (RAY == 1)
  1980.    {
  1981. #ifndef XFRACT
  1982.       fprintf(File_Ptr1, " %Fs%Fs\n", (char far *)end, (char far *)triangle);
  1983. #else
  1984.       fprintf(File_Ptr1, " %s%s\n", end, triangle);
  1985. #endif
  1986.       if (!BRIEF)
  1987.       {
  1988. #ifndef XFRACT
  1989.          fprintf(File_Ptr1, "  %Fs"
  1990.                  "      %Fs%Fs% #4.4f %Fs% #4.4f %Fs% #4.4f\n"
  1991.                  "%Fs"
  1992.                  " %Fs%Fs",
  1993. #else
  1994.          fprintf(File_Ptr1,
  1995.                  "  %s   %s%s% #4.4f %s% #4.4f %s% #4.4f\n%s %s%s",
  1996. #endif
  1997.                  (char far *)texture,
  1998.                  (char far *)s_color, 
  1999.                  (char far *)red,   c[0], 
  2000.                  (char far *)green, c[1], 
  2001.                  (char far *)blue,  c[2],
  2002.                  (char far *)frac_texture,
  2003.                  (char far *)end, 
  2004.                  (char far *)texture);
  2005.       }
  2006. #ifndef XFRACT
  2007.       fprintf(File_Ptr1, "  %Fs%Fs  %Fs%Fs",
  2008. #else
  2009.       fprintf(File_Ptr1, "  %s%s  %s%s",
  2010. #endif
  2011.               (char far *)s_color, (char far *)frac_default,
  2012.               (char far *)end, (char far *)object);
  2013.       triangle_bounds(pt_t);    /* update bounding info */
  2014.    }
  2015.    if (RAY == 2)
  2016.       fprintf(File_Ptr1, "}");
  2017.    if (RAY == 3 && !BRIEF)
  2018.       fprintf(File_Ptr1, s_n);
  2019.  
  2020.    if (RAY != 7)
  2021.       fprintf(File_Ptr1, s_n);
  2022.  
  2023.    return (0);
  2024. }
  2025.  
  2026. /********************************************************************/
  2027. /*                                                                  */
  2028. /*  This routine calculates the min and max values of a triangle    */
  2029. /*  for use in creating ray tracer data files. The values of min    */
  2030. /*  and max x, y, and z are assumed to be global.                   */
  2031. /*                                                                  */
  2032. /********************************************************************/
  2033.  
  2034. static void _fastcall triangle_bounds(float pt_t[3][3])
  2035. {
  2036.    int i, j;
  2037.  
  2038.    for (i = 0; i <= 2; i++)
  2039.       for (j = 0; j <= 2; j++)
  2040.       {
  2041.          if (pt_t[i][j] < min_xyz[j])
  2042.             min_xyz[j] = pt_t[i][j];
  2043.          if (pt_t[i][j] > max_xyz[j])
  2044.             max_xyz[j] = pt_t[i][j];
  2045.       }
  2046.    return;
  2047. }
  2048.  
  2049. /********************************************************************/
  2050. /*                                                                  */
  2051. /*  This routine starts a composite object for ray trace data files */
  2052. /*                                                                  */
  2053. /********************************************************************/
  2054.  
  2055. static int _fastcall start_object(void)
  2056. {
  2057.    if (RAY != 1)
  2058.       return (0);
  2059.  
  2060.    /* Reset the min/max values, for bounding box  */
  2061.    min_xyz[0] = min_xyz[1] = min_xyz[2] = (float)999999.0;
  2062.    max_xyz[0] = max_xyz[1] = max_xyz[2] = (float)-999999.0;
  2063.  
  2064. #ifndef XFRACT
  2065.    fprintf(File_Ptr1, "%Fs\n", (char far *)composite);
  2066. #else
  2067.    fprintf(File_Ptr1, "%s\n", composite);
  2068. #endif
  2069.    return (0);
  2070. }
  2071.  
  2072. /********************************************************************/
  2073. /*                                                                  */
  2074. /*  This routine adds a bounding box for the triangles drawn        */
  2075. /*  in the last block and completes the composite object created.   */
  2076. /*  It uses the globals min and max x,y and z calculated in         */
  2077. /*  z calculated in Triangle_Bounds().                              */
  2078. /*                                                                  */
  2079. /********************************************************************/
  2080.  
  2081. static int _fastcall end_object(int triout)
  2082. {
  2083.    if (RAY == 7)
  2084.       return (0);
  2085.    if (RAY == 1)
  2086.    {
  2087.       if (triout)
  2088.       {
  2089.          /* Make sure the bounding box is slightly larger than the object */
  2090.          int i;
  2091.          for (i = 0; i <= 2; i++)
  2092.          {
  2093.             if (min_xyz[i] == max_xyz[i])
  2094.             {
  2095.                min_xyz[i] -= (float)0.01;
  2096.                max_xyz[i] += (float)0.01;
  2097.             }
  2098.             else
  2099.             {
  2100.                min_xyz[i] -= (max_xyz[i] - min_xyz[i]) * (float)0.01;
  2101.                max_xyz[i] += (max_xyz[i] - min_xyz[i]) * (float)0.01;
  2102.             }
  2103.          }
  2104.  
  2105.          /* Add the bounding box info */
  2106. #ifndef XFRACT
  2107.          fprintf(File_Ptr1, "%Fs  %Fs", (char far *)bnd_by, (char far *)inter);
  2108. #else
  2109.          fprintf(File_Ptr1, "%s  %s", bnd_by, inter);
  2110. #endif
  2111.          fprintf(File_Ptr1, fmt, (char far *)plane, (char far *)m1, (char far *)z, (char far *)z, -min_xyz[0], (char far *)end, (char far *)plane);
  2112.          fprintf(File_Ptr1, fmt, (char far *)plane, (char far *)one, (char far *)z, (char far *)z, max_xyz[0], (char far *)end, (char far *)plane);
  2113.          fprintf(File_Ptr1, fmt, (char far *)plane, (char far *)z, (char far *)m1, (char far *)z, -min_xyz[1], (char far *)end, (char far *)plane);
  2114.          fprintf(File_Ptr1, fmt, (char far *)plane, (char far *)z, (char far *)one, (char far *)z, max_xyz[1], (char far *)end, (char far *)plane);
  2115.          fprintf(File_Ptr1, fmt, (char far *)plane, (char far *)z, (char far *)z, (char far *)m1, -min_xyz[2], (char far *)end, (char far *)plane);
  2116.          fprintf(File_Ptr1, fmt, (char far *)plane, (char far *)z, (char far *)z, (char far *)one, max_xyz[2], (char far *)end, (char far *)plane);
  2117. #ifndef XFRACT
  2118.          fprintf(File_Ptr1, "  %Fs%Fs%Fs", (char far *)end, 
  2119.                 (char far *)inter, (char far *)end_bnd);
  2120. #else
  2121.          fprintf(File_Ptr1, "  %s%s%s", end, inter, end_bnd);
  2122. #endif
  2123.       }
  2124.  
  2125.       /* Complete the composite object statement */
  2126. #ifndef XFRACT
  2127.       fprintf(File_Ptr1, "%Fs%Fs\n", (char far *)end, (char far *)composite);
  2128. #else
  2129.       fprintf(File_Ptr1, "%s%s\n", end, composite);
  2130. #endif
  2131.    }
  2132.  
  2133.    if (RAY != 6 && RAY != 5)
  2134.       fprintf(File_Ptr1, s_n);    /* EB & DG: too many newlines */
  2135.  
  2136.    return (0);
  2137. }
  2138.  
  2139. static void line3d_cleanup(void)
  2140. {
  2141.    int i, j;
  2142.    if (RAY && File_Ptr1)
  2143.    {                            /* Finish up the ray tracing files */
  2144.       static FCODE n_ta[] = {"{ No. Of Triangles = "};
  2145.       if (RAY != 5 && RAY != 7)
  2146.          fprintf(File_Ptr1, s_n); /* EB & DG: too many newlines */
  2147.       if (RAY == 2)
  2148.          fprintf(File_Ptr1, "\n\n//");
  2149.       if (RAY == 4)
  2150.          fprintf(File_Ptr1, "\n\n#");
  2151.  
  2152.       if (RAY == 5)
  2153. #ifndef XFRACT
  2154.          /* EB & DG: end grid aggregate */
  2155.          fprintf(File_Ptr1, "end\n\n/*good landscape:*/\n%Fs%Fs\n/*", 
  2156.             (char far *)grid, (char far *)grid2);     
  2157. #else
  2158.          /* EB & DG: end grid aggregate */
  2159.          fprintf(File_Ptr1, "end\n\n/*good landscape:*/\n%s%s\n/*", 
  2160.             grid, grid2);       
  2161. #endif
  2162.       if (RAY == 6)
  2163.       {
  2164. #ifndef XFRACT
  2165.          fprintf(File_Ptr1, "%Fs", (char far *)acro_s2);
  2166. #else
  2167.          fprintf(File_Ptr1, "%s", acro_s2);
  2168. #endif
  2169.          for (i = 0; i < RO; i++)
  2170.             for (j = 0; j <= CO_MAX; j++)
  2171.             {
  2172.                if (j < CO_MAX)
  2173.                   fprintf(File_Ptr1, f2, i, j, i, j + 1);
  2174.                if (i < RO - 1)
  2175.                   fprintf(File_Ptr1, f2, i, j, i + 1, j);
  2176.                if (i && i < RO && j < CO_MAX)
  2177.                   fprintf(File_Ptr1, f2, i, j, i - 1, j + 1);
  2178.             }
  2179.          fprintf(File_Ptr1, "\n\n--");
  2180.       }
  2181.       if (RAY != 7)
  2182. #ifndef XFRACT
  2183.          fprintf(File_Ptr1, "%Fs%ld }*/\n\n", (char far *)n_ta, num_tris);
  2184. #else
  2185.          fprintf(File_Ptr1, "%s%ld }*/\n\n", n_ta, num_tris);  
  2186. #endif
  2187.       if (RAY == 7)
  2188.          fprintf(File_Ptr1, dxf_end);
  2189.       fclose(File_Ptr1);
  2190.       File_Ptr1 = NULL;
  2191.    }
  2192.    if (Targa_Out)
  2193.    {                            /* Finish up targa files */
  2194.       T_header_24 = 18;         /* Reset Targa header size */
  2195.       enddisk();
  2196.       if (!debugflag && T_Safe && !error && Targa_Overlay)
  2197.       {
  2198.          remove(light_name);
  2199.          rename(targa_temp, light_name);
  2200.       }
  2201.       if (!debugflag && Targa_Overlay)
  2202.          remove(targa_temp);
  2203.    }
  2204.    usr_floatflag &= 1;          /* strip second bit */
  2205.    error = T_Safe = 0;
  2206. }
  2207.  
  2208. static int first_time(int linelen, VECTOR v)
  2209. {
  2210.    int err;
  2211.    MATRIX lightm;               /* m w/no trans, keeps obj. on screen */
  2212.    float twocosdeltatheta;
  2213.    double xval, yval, zval;     /* rotation values */
  2214.    /* corners of transformed xdotx by ydots x colors box */
  2215.    double xmin, ymin, zmin, xmax, ymax, zmax;
  2216.    int i, j;
  2217.    double v_length;
  2218.    VECTOR origin, direct, tmp;
  2219.    float theta, theta1, theta2; /* current,start,stop latitude */
  2220.    float phi1, phi2;            /* current start,stop longitude */
  2221.    float deltatheta;            /* increment of latitude */
  2222.    outln_cleanup = line3d_cleanup;
  2223.  
  2224.    calctime = evenoddrow = 0;
  2225.    /* mark as in-progress, and enable <tab> timer display */
  2226.    calc_status = 1;
  2227.  
  2228.    IAmbient = (unsigned int) (255 * (float) (100 - Ambient) / 100.0);
  2229.    if (IAmbient < 1)
  2230.       IAmbient = 1;
  2231.  
  2232.    num_tris = 0;
  2233.  
  2234.    /* Open file for RAY trace output and write header */
  2235.    if (RAY)
  2236.    {
  2237.       RAY_Header();
  2238.       xxadjust = yyadjust = 0;  /* Disable shifting in ray tracing */
  2239.       xshift = yshift = 0;
  2240.    }
  2241.  
  2242.    CO_MAX = CO = RO = 0;
  2243.  
  2244.    upr_lwr[0] = (BYTE)(xdots & 0xff);
  2245.    upr_lwr[1] = (BYTE)(xdots >> 8);
  2246.    upr_lwr[2] = (BYTE)(ydots & 0xff);
  2247.    upr_lwr[3] = (BYTE)(ydots >> 8);
  2248.    line_length1 = 3 * xdots;    /* line length @ 3 bytes per pixel  */
  2249.    error = 0;
  2250.  
  2251.    if (whichimage < 2)
  2252.       T_Safe = 0; /* Not safe yet to mess with the source image */
  2253.  
  2254.    if (Targa_Out && !((glassestype == 1 || glassestype == 2) 
  2255.                  && whichimage == 2))
  2256.    {
  2257.       if (Targa_Overlay)
  2258.       {
  2259.          /* Make sure target file is a supportable Targa File */
  2260.          if (targa_validate(light_name))
  2261.             return (-1);
  2262.       }
  2263.       else
  2264.       {
  2265.          check_writefile(light_name, ".tga");
  2266.          if (startdisk1(light_name, NULL, 0))   /* Open new file */
  2267.             return (-1);
  2268.       }
  2269.    }
  2270.  
  2271.    rand_factor = 14 - RANDOMIZE;
  2272.  
  2273.    zcoord = filecolors;
  2274.  
  2275.    if((err=line3dmem()) != 0)
  2276.       return(err);
  2277.  
  2278.  
  2279.    /* get scale factors */
  2280.    sclx = XSCALE / 100.0;
  2281.    scly = YSCALE / 100.0;
  2282.    if (ROUGH)
  2283.       sclz = -ROUGH / 100.0;
  2284.    else
  2285.       rscale = sclz = -0.0001;  /* if rough=0 make it very flat but plot
  2286.                                  * something */
  2287.  
  2288.    /* aspect ratio calculation - assume screen is 4 x 3 */
  2289.    aspect = (double) xdots *.75 / (double) ydots;
  2290.  
  2291.    if (SPHERE == FALSE)         /* skip this slow stuff in sphere case */
  2292.    {
  2293.       /*********************************************************************/
  2294.       /* What is done here is to create a single matrix, m, which has      */
  2295.       /* scale, rotation, and shift all combined. This allows us to use    */
  2296.       /* a single matrix to transform any point. Additionally, we create   */
  2297.       /* two perspective vectors.                                          */
  2298.       /*                                                                   */
  2299.       /* Start with a unit matrix. Add scale and rotation. Then calculate  */
  2300.       /* the perspective vectors. Finally add enough translation to center */
  2301.       /* the final image plus whatever shift the user has set.             */
  2302.       /*********************************************************************/
  2303.  
  2304.       /* start with identity */
  2305.       identity(m);
  2306.       identity(lightm);
  2307.  
  2308.       /* translate so origin is in center of box, so that when we rotate */
  2309.       /* it, we do so through the center */
  2310.       trans((double) xdots / (-2.0), (double) ydots / (-2.0),
  2311.             (double) zcoord / (-2.0), m);
  2312.       trans((double) xdots / (-2.0), (double) ydots / (-2.0),
  2313.             (double) zcoord / (-2.0), lightm);
  2314.  
  2315.       /* apply scale factors */
  2316.       scale(sclx, scly, sclz, m);
  2317.       scale(sclx, scly, sclz, lightm);
  2318.  
  2319.       /* rotation values - converting from degrees to radians */
  2320.       xval = XROT / 57.29577;
  2321.       yval = YROT / 57.29577;
  2322.       zval = ZROT / 57.29577;
  2323.  
  2324.       if (RAY)
  2325.       {
  2326.          xval = yval = zval = 0;
  2327.       }
  2328.  
  2329.       xrot(xval, m);
  2330.       xrot(xval, lightm);
  2331.       yrot(yval, m);
  2332.       yrot(yval, lightm);
  2333.       zrot(zval, m);
  2334.       zrot(zval, lightm);
  2335.  
  2336.       /* Find values of translation that make all x,y,z negative */
  2337.       /* m current matrix */
  2338.       /* 0 means don't show box */
  2339.       /* returns minimum and maximum values of x,y,z in fractal */
  2340.       corners(m, 0, &xmin, &ymin, &zmin, &xmax, &ymax, &zmax);
  2341.    }
  2342.  
  2343.    /* perspective 3D vector - lview[2] == 0 means no perspective */
  2344.  
  2345.    /* set perspective flag */
  2346.    persp = 0;
  2347.    if (ZVIEWER != 0)
  2348.    {
  2349.       persp = 1;
  2350.       if (ZVIEWER < 80)         /* force float */
  2351.          usr_floatflag |= 2;    /* turn on second bit */
  2352.    }
  2353.  
  2354.    /* set up view vector, and put viewer in center of screen */
  2355.    lview[0] = xdots >> 1;
  2356.    lview[1] = ydots >> 1;
  2357.  
  2358.    /* z value of user's eye - should be more negative than extreme negative
  2359.     * part of image */
  2360.    if (SPHERE)                  /* sphere case */
  2361.       lview[2] = -(long) ((double) ydots * (double) ZVIEWER / 100.0);
  2362.    else                         /* non-sphere case */
  2363.       lview[2] = (long) ((zmin - zmax) * (double) ZVIEWER / 100.0);
  2364.  
  2365.    view[0] = lview[0];
  2366.    view[1] = lview[1];
  2367.    view[2] = lview[2];
  2368.    lview[0] = lview[0] << 16;
  2369.    lview[1] = lview[1] << 16;
  2370.    lview[2] = lview[2] << 16;
  2371.  
  2372.    if (SPHERE == FALSE)         /* sphere skips this */
  2373.    {
  2374.       /* translate back exactly amount we translated earlier plus enough to
  2375.        * center image so maximum values are non-positive */
  2376.       trans(((double) xdots - xmax - xmin) / 2, 
  2377.             ((double) ydots - ymax - ymin) / 2, -zmax, m);
  2378.  
  2379.       /* Keep the box centered and on screen regardless of shifts */
  2380.       trans(((double) xdots - xmax - xmin) / 2, 
  2381.             ((double) ydots - ymax - ymin) / 2, -zmax, lightm);
  2382.  
  2383.       trans((double) (xshift), (double) (-yshift), 0.0, m);
  2384.  
  2385.       /* matrix m now contains ALL those transforms composed together !!
  2386.        * convert m to long integers shifted 16 bits */
  2387.       for (i = 0; i < 4; i++)
  2388.          for (j = 0; j < 4; j++)
  2389.             llm[i][j] = (long) (m[i][j] * 65536.0);
  2390.  
  2391.    }
  2392.    else
  2393.       /* sphere stuff goes here */
  2394.    {
  2395.       /* Sphere is on side - north pole on right. Top is -90 degrees
  2396.        * latitude; bottom 90 degrees */
  2397.  
  2398.       /* Map X to this LATITUDE range */
  2399.       theta1 = (float) (THETA1 * PI / 180.0);
  2400.       theta2 = (float) (THETA2 * PI / 180.0);
  2401.  
  2402.       /* Map Y to this LONGITUDE range */
  2403.       phi1 = (float) (PHI1 * PI / 180.0);
  2404.       phi2 = (float) (PHI2 * PI / 180.0);
  2405.  
  2406.       theta = theta1;
  2407.  
  2408.       /*********************************************************************/
  2409.       /* Thanks to Hugh Bray for the following idea: when calculating      */
  2410.       /* a table of evenly spaced sines or cosines, only a few initial     */
  2411.       /* values need be calculated, and the remaining values can be        */
  2412.       /* gotten from a derivative of the sine/cosine angle sum formula     */
  2413.       /* at the cost of one multiplication and one addition per value!     */
  2414.       /*                                                                   */
  2415.       /* This idea is applied once here to get a complete table for        */
  2416.       /* latitude, and near the bottom of this routine to incrementally    */
  2417.       /* calculate longitude.                                              */
  2418.       /*                                                                   */
  2419.       /* Precalculate 2*cos(deltaangle), sin(start) and sin(start+delta).  */
  2420.       /* Then apply recursively:                                           */
  2421.       /* sin(angle+2*delta) = sin(angle+delta) * 2cosdelta - sin(angle)    */
  2422.       /*                                                                   */
  2423.       /* Similarly for cosine. Neat!                                       */
  2424.       /*********************************************************************/
  2425.  
  2426.       deltatheta = (float) (theta2 - theta1) / (float) linelen;
  2427.  
  2428.       /* initial sin,cos theta */
  2429.       sinthetaarray[0] = (float) sin((double) theta);
  2430.       costhetaarray[0] = (float) cos((double) theta);
  2431.       sinthetaarray[1] = (float) sin((double) (theta + deltatheta));
  2432.       costhetaarray[1] = (float) cos((double) (theta + deltatheta));
  2433.  
  2434.       /* sin,cos delta theta */
  2435.       twocosdeltatheta = (float) (2.0 * cos((double) deltatheta));
  2436.  
  2437.       /* build table of other sin,cos with trig identity */
  2438.       for (i = 2; i < (int) linelen; i++)
  2439.       {
  2440.          sinthetaarray[i] = sinthetaarray[i - 1] * twocosdeltatheta -
  2441.             sinthetaarray[i - 2];
  2442.          costhetaarray[i] = costhetaarray[i - 1] * twocosdeltatheta -
  2443.             costhetaarray[i - 2];
  2444.       }
  2445.  
  2446.       /* now phi - these calculated as we go - get started here */
  2447.       deltaphi = (float) (phi2 - phi1) / (float) height;
  2448.  
  2449.       /* initial sin,cos phi */
  2450.  
  2451.       sinphi = oldsinphi1 = (float) sin((double) phi1);
  2452.       cosphi = oldcosphi1 = (float) cos((double) phi1);
  2453.       oldsinphi2 = (float) sin((double) (phi1 + deltaphi));
  2454.       oldcosphi2 = (float) cos((double) (phi1 + deltaphi));
  2455.  
  2456.       /* sin,cos delta phi */
  2457.       twocosdeltaphi = (float) (2.0 * cos((double) deltaphi));
  2458.  
  2459.  
  2460.       /* affects how rough planet terrain is */
  2461.       if (ROUGH)
  2462.          rscale = .3 * ROUGH / 100.0;
  2463.  
  2464.       /* radius of planet */
  2465.       R = (double) (ydots) / 2;
  2466.  
  2467.       /* precalculate factor */
  2468.       rXrscale = R * rscale;
  2469.  
  2470.       sclz = sclx = scly = RADIUS / 100.0;      /* Need x,y,z for RAY */
  2471.  
  2472.       /* adjust x scale factor for aspect */
  2473.       sclx *= aspect;
  2474.  
  2475.       /* precalculation factor used in sphere calc */
  2476.       Rfactor = rscale * R / (double) zcoord;
  2477.  
  2478.       if (persp)                /* precalculate fudge factor */
  2479.       {
  2480.          double radius;
  2481.          double zview;
  2482.          double angle;
  2483.  
  2484.          xcenter = xcenter << 16;
  2485.          ycenter = ycenter << 16;
  2486.  
  2487.          Rfactor *= 65536.0;
  2488.          R *= 65536.0;
  2489.  
  2490.          /* calculate z cutoff factor attempt to prevent out-of-view surfaces
  2491.           * from being written */
  2492.          zview = -(long) ((double) ydots * (double) ZVIEWER / 100.0);
  2493.          radius = (double) (ydots) / 2;
  2494.          angle = atan(-radius / (zview + radius));
  2495.          zcutoff = -radius - sin(angle) * radius;
  2496.          zcutoff *= 1.1;        /* for safety */
  2497.          zcutoff *= 65536L;
  2498.       }
  2499.    }
  2500.  
  2501.    /* set fill plot function */
  2502.    if (FILLTYPE != 3)
  2503.       fillplot = interpcolor;
  2504.    else
  2505.    {
  2506.       fillplot = clipcolor;
  2507.  
  2508.       if (transparent[0] || transparent[1])
  2509.          /* If transparent colors are set */
  2510.          fillplot = T_clipcolor;/* Use the transparent plot function  */
  2511.    }
  2512.  
  2513.    /* Both Sphere and Normal 3D */
  2514.    direct[0] = light_direction[0] = XLIGHT;
  2515.    direct[1] = light_direction[1] = -YLIGHT;
  2516.    direct[2] = light_direction[2] = ZLIGHT;
  2517.  
  2518.    /* Needed because sclz = -ROUGH/100 and light_direction is transformed in
  2519.     * FILLTYPE 6 but not in 5. */
  2520.    if (FILLTYPE == 5)
  2521.       direct[2] = light_direction[2] = -ZLIGHT;
  2522.  
  2523.    if (FILLTYPE == 6)           /* transform light direction */
  2524.    {
  2525.       /* Think of light direction  as a vector with tail at (0,0,0) and head
  2526.        * at (light_direction). We apply the transformation to BOTH head and
  2527.        * tail and take the difference */
  2528.  
  2529.       v[0] = 0.0;
  2530.       v[1] = 0.0;
  2531.       v[2] = 0.0;
  2532.       vmult(v, m, v);
  2533.       vmult(light_direction, m, light_direction);
  2534.  
  2535.       for (i = 0; i < 3; i++)
  2536.          light_direction[i] -= v[i];
  2537.    }
  2538.    normalize_vector(light_direction);
  2539.  
  2540.    if (preview && showbox)
  2541.    {
  2542.       normalize_vector(direct);
  2543.  
  2544.       /* move light vector to be more clear with grey scale maps */
  2545.       origin[0] = (3 * xdots) / 16;
  2546.       origin[1] = (3 * ydots) / 4;
  2547.       if (FILLTYPE == 6)
  2548.          origin[1] = (11 * ydots) / 16;
  2549.  
  2550.       origin[2] = 0.0;
  2551.  
  2552.       v_length = min(xdots, ydots) / 2;
  2553.       if (persp && ZVIEWER <= P)
  2554.          v_length *= (long) (P + 600) / ((long) (ZVIEWER + 600) * 2);
  2555.  
  2556.       /* Set direct[] to point from origin[] in direction of untransformed
  2557.        * light_direction (direct[]). */
  2558.       for (i = 0; i < 3; i++)
  2559.          direct[i] = origin[i] + direct[i] * v_length;
  2560.  
  2561.       /* center light box */
  2562.       for (i = 0; i < 2; i++)
  2563.       {
  2564.          tmp[i] = (direct[i] - origin[i]) / 2;
  2565.          origin[i] -= tmp[i];
  2566.          direct[i] -= tmp[i];
  2567.       }
  2568.  
  2569.       /* Draw light source vector and box containing it, draw_light_box will
  2570.        * transform them if necessary. */
  2571.       draw_light_box(origin, direct, lightm);
  2572.       /* draw box around original field of view to help visualize effect of
  2573.        * rotations 1 means show box - xmin etc. do nothing here */
  2574.       if (!SPHERE)
  2575.          corners(m, 1, &xmin, &ymin, &zmin, &xmax, &ymax, &zmax);
  2576.    }
  2577.  
  2578.    /* bad has values caught by clipping */
  2579.    f_bad.x = bad.x = bad_value;
  2580.    f_bad.y = bad.y = bad_value;
  2581.    f_bad.color = bad.color = bad_value;
  2582.    for (i = 0; i < (int) linelen; i++)
  2583.    {
  2584.       lastrow[i] = bad;
  2585.       f_lastrow[i] = f_bad;
  2586.    }
  2587.    got_status = 3;
  2588.    if (iit > 0)
  2589.    {
  2590.       load_mat(m);              /* load matrix into iit registers */
  2591.       mult_vec = mult_vec_iit;
  2592.    }
  2593.    else
  2594.       mult_vec = mult_vec_c;
  2595.    return (0);
  2596. } /* end of once-per-image intializations */
  2597.  
  2598. /*
  2599.    This pragma prevents optimizer failure in MSC/C++ 7.0. Program compiles ok
  2600.    without pragma, but error message is real ugly, paraphrasing loosely,
  2601.    something like "optimizer screwed up big time, call Bill Gates collect ...  
  2602.    (Note: commented out pragma because we removed the compiler "/Og" option
  2603.     in MAKEFRACT.BAT - left these notes as a warning...
  2604. */
  2605. #ifdef _MSC_VER
  2606. #if (_MSC_VER >= 600)
  2607. /* #pragma optimize( "g", off ) */
  2608. #endif
  2609. #endif
  2610.  
  2611. static int line3dmem(void)
  2612. {
  2613.    /*********************************************************************/
  2614.    /*  Memory allocation - assumptions - a 64K segment starting at      */
  2615.    /*  extraseg has been grabbed. It may have other purposes elsewhere, */
  2616.    /*  but it is assumed that it is totally free for use here. Our      */
  2617.    /*  strategy is to assign all the far pointers needed here to various*/
  2618.    /*  spots in the extra segment, depending on the pixel dimensions of */
  2619.    /*  the video mode, and check whether we have run out. There is      */
  2620.    /*  basically one case where the extra segment is not big enough     */
  2621.    /*  -- SPHERE mode with a fill type that uses putatriangle() (array  */
  2622.    /*  minmax_x) at the largest legal resolution of MAXPIXELSxMAXPIXELS */
  2623.    /*  or thereabouts. In that case we use farmemalloc to grab memory   */
  2624.    /*  for minmax_x. This memory is never freed.                        */
  2625.    /*********************************************************************/
  2626.    long check_extra;  /* keep track ofd extraseg array use */ 
  2627.  
  2628.    /* lastrow stores the previous row of the original GIF image for
  2629.       the purpose of filling in gaps with triangle procedure */
  2630.    /* first 8k of extraseg now used in decoder TW 3/95 */
  2631.    lastrow = MK_FP(extraseg, (MAX_CODES+1)*sizeof(short));
  2632.  
  2633.    check_extra = (MAX_CODES+1)*sizeof(short) + sizeof(*lastrow) * xdots;
  2634.    if (SPHERE)
  2635.    {
  2636.       sinthetaarray = (float far *) (lastrow + xdots);
  2637.       check_extra += sizeof(*sinthetaarray) * xdots;
  2638.       costhetaarray = (float far *) (sinthetaarray + xdots);
  2639.       check_extra += sizeof(*costhetaarray) * xdots;
  2640.       f_lastrow = (struct f_point far *) (costhetaarray + xdots);
  2641.    }
  2642.    else
  2643.       f_lastrow = (struct f_point far *) (lastrow + xdots);
  2644.    check_extra += sizeof(*f_lastrow) * (xdots);
  2645.    if (pot16bit)
  2646.    {
  2647.       fraction = (BYTE far *) (f_lastrow + xdots);
  2648.       check_extra += sizeof(*fraction) * xdots;
  2649.    }
  2650.    minmax_x = (struct minmax *) NULL;
  2651.  
  2652.    /* these fill types call putatriangle which uses minmax_x */
  2653.    if (FILLTYPE == 2 || FILLTYPE == 3 || FILLTYPE == 5 || FILLTYPE == 6)
  2654.    {
  2655.       /* end of arrays if we use extra segement */
  2656.       check_extra += sizeof(struct minmax) * ydots;
  2657.       if (check_extra > (1L << 16))     /* run out of extra segment? */
  2658.       {
  2659.          static FCODE msg[] = {"farmemalloc minmax"};
  2660.          static struct minmax far *got_mem = NULL;
  2661.          if(debugflag == 2222)
  2662.             stopmsg(0,msg);
  2663.          /* not using extra segment so decrement check_extra */
  2664.          check_extra -= sizeof(struct minmax) * ydots;
  2665.          if (got_mem == NULL)
  2666.             got_mem = (struct minmax far *) (farmemalloc(MAXPIXELS *
  2667.                                                     sizeof(struct minmax)));
  2668.          if (got_mem)
  2669.             minmax_x = got_mem;
  2670.          else
  2671.             return (-1);
  2672.       }
  2673.       else /* ok to use extra segment */
  2674.       {
  2675.          if (pot16bit)
  2676.             minmax_x = (struct minmax far *) (fraction + xdots);
  2677.          else
  2678.             minmax_x = (struct minmax far *) (f_lastrow + xdots);
  2679.       }
  2680.    }
  2681.    if (debugflag == 2222 || check_extra > (1L << 16))
  2682.    {
  2683.       char tmpmsg[70];
  2684.       static FCODE extramsg[] = {" of extra segment"};
  2685. #ifndef XFRACT
  2686.       sprintf(tmpmsg, "used %ld%Fs", check_extra, (char far *)extramsg);
  2687. #else
  2688.       sprintf(tmpmsg, "used %ld%s", check_extra, extramsg);
  2689. #endif
  2690.       stopmsg(4, tmpmsg);
  2691.    }
  2692.    return(0);
  2693. }
  2694.  
  2695. #ifdef _MSC_VER
  2696. #if (_MSC_VER >= 600)
  2697. #pragma optimize( "g", on )
  2698. #endif
  2699. #endif
  2700.  
  2701.